Lor*_*156 4 c++ g++ visual-c++ c++17
我为不可复制的类创建了这个基类:
class non_copyable
{
public:
non_copyable(const non_copyable&) = delete;
non_copyable& operator=(const non_copyable&) = delete;
virtual ~non_copyable() = default;
protected:
non_copyable() = default;
};
Run Code Online (Sandbox Code Playgroud)
然后我创建了这个派生类:
class manager
: public non_copyable
{
public:
manager()
{
}
std::string s;
};
Run Code Online (Sandbox Code Playgroud)
我能够创建一个类的实例并返回如下:
manager get()
{
return manager();
}
Run Code Online (Sandbox Code Playgroud)
我认为这是不可能的,因为删除了复制构造函数并删除了隐式生成的移动构造函数,因为存在用户定义(已删除)的复制构造函数.
此代码使用MinGW-64 7.2编译,但不与MSVC 2017编译,并产生以下消息:
函数"manager :: operator =(const manager&)throw()"(隐式声明)无法引用 - 它是一个已删除的函数
这是编译器的问题,C++设计允许还是我做错了什么?
在c++17中,纯右值表达式在逻辑上不是对象。在c++14中,从逻辑上讲,它们是对象(或者更确切地说,它们创建了它们)。
现在,纯右值表达式是关于如何创建对象的指令。在某些情况下,这些指令适用于创建临时或非临时对象。
这更普遍地称为“保证省略”。但实际上,它只是在许多情况下(不是全部)消除了任何省略的需要。
manager get() {
return manager();
}
Run Code Online (Sandbox Code Playgroud)
在c++14 manager()
中是创建对象的纯右值表达式。返回值是另一个纯右值。可以通过合并其身份和生命周期的这两个对象来消除manager()
从到 返回值的复制或移动。get
在c++17 manager()
中是纯右值,就像 的返回值一样get()
。您不需要“复制”或“移动”有关如何创建对象的说明,对象也不是。return 只是告诉返回值“这是您需要的说明”。
manager foo = get();
Run Code Online (Sandbox Code Playgroud)
在这里,我们从纯右值构造foo
——从如何创建manager
. 没有创建临时对象;相反,我们只是按照 的纯右值返回的指示构造对象get()
。
在c++14中,我们有一个临时管理器对象,其生命周期可以用命名对象来消除foo
。
这种省略和“直接”使用纯右值在运行时的效果非常相似,但一个涉及我们稍后消除的逻辑移动或复制构造函数调用,另一个从一开始就没有第二个对象。
至于为什么 MSVC2017 的行为有所不同,他们对c++11的实现仍然不完整(无可否认,每年都以较小的方式实现,但我仍然被烧伤),更不用说c++17了。