当前位置:  开发笔记 > 编程语言 > 正文

是否可以返回不可移动,不可复制类型的实例?

如何解决《是否可以返回不可移动,不可复制类型的实例?》经验,为你挑选了2个好方法。

在VS2013更新5中,我有这个:

class Lock
{
public:
    Lock(CriticalSection& cs) : cs_(cs)
    {}

    Lock(const Lock&) = delete;
    Lock(Lock&&) = delete;
    Lock& operator=(const Lock&) = delete;
    Lock& operator=(Lock&&) = delete;

    ~Lock()
    {
        LeaveCriticalSection(&(cs_.cs_));
    }

private:
    CriticalSection& cs_;
};


class CriticalSection
{
    CRITICAL_SECTION cs_;
public:
    CriticalSection(const CriticalSection&) = delete;
    CriticalSection& operator=(const CriticalSection&) = delete;
    CriticalSection(CriticalSection&&) = delete;
    CriticalSection& operator=(CriticalSection&&) = delete;

    CriticalSection()
    {
        InitializeCriticalSection(&cs_);
    }

    ~CriticalSection()
    {
        DeleteCriticalSection(&cs_);
    }

    // Usage:  auto lock = criticalSection.MakeLock();
    Lock MakeLock()
    {
        EnterCriticalSection(&cs_);
        return Lock(*this);
    }
}

MakeLock返回不可移动,不可复制类型的实例.这似乎工作正常.但是,Visual Studio intellisense确实强调了红色的返回,并警告说Lock的移动构造函数不能被引用,因为它是一个已删除的函数.

我试图理解为什么这有效,如果它是标准符合C++或只是MSVC特有的东西.我猜回归是有效的,因为构建返回值的需要可以被优化掉,所以intellisense警告会警告某些事情 - 实际上 - 实际上不会发生.

我想我在某处读到C++会标准化以确保返回值优化总是会发生.

那么,这个符合C++的代码是否会继续在未来的编译器中运行?

PS我意识到std::mutexstd::lock_guard可能取代它.



1> Martin Bonne..:

如果编译,则编译器中存在错误.VC2015无法正确编译它.

class Foo
{
public:
    Foo() {}
    Foo(const Foo&) = delete;
    Foo(Foo&&) = delete;
};


Foo Bar()
{
    return Foo();
}

给我:

xxx.cpp(327): error C2280: 'Foo::Foo(Foo &&)': attempting to reference a deleted function

和g ++ 4.9说:

error : use of deleted function 'Foo::Foo(Foo&&)'

标准非常清楚,复制构造函数或移动构造函数必须存在且可访问,即使RVO意味着它未被调用.



2> rubenvb..:

在C++ 17中,Martin Bonner的答案中的代码是合法的.

编译器不仅被允许,而且还有义务忽略该副本.Clang和GCC的实例.C++ 17 6.3.2/2(强调我的):

[...] [注意:如果操作数不是prvalue或者其类型与函数的返回类型不同,则返回语句可能涉及调用构造函数以执行操作数的复制或移动.如果返回自动存储持续时间变量(10.9.5),则可以省略与返回语句相关联的复制操作或将其转换为移动操作. - 结束说明]

这里的prvalue意味着一个临时的.有关确切的定义和大量示例,请参见此处.

在C++ 11中,这确实是非法的.但它很容易解决,通过在return语句中使用大括号初始化,您可以在调用站点位置构造返回值,完美地绕过了经常被省略的复制构造函数的要求.C++ 11 6.6.3/2:

[...]带有braced-init-list的return语句通过copy-list-initialization(8.5.4)从指定的初始化列表初始化要从函数返回的对象或引用.[...]

复制列表初始化意味着只调用构造函数.不涉及复制/移动构造函数.

Clang和GCC的实例.

不幸的是,它既不适用于Visual Studio编译器的任何最新版本,也很难受,并且保持其糟糕的C++一致性声誉.返回像这样的非可复制对象是一个非常强大的构造,用于std::lock_guard从函数返回例如s(允许您轻松地保持std::mutex成员私有)等.

推荐阅读
oDavid_仔o_880
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有