为什么g ++允许返回不可复制的类?

时间:2018-03-12 20:24:03

标签: c++ visual-c++ g++ c++17

我为不可复制的类创建了这个基类:

class manager
    : public non_copyable
{
public:
    manager()
    {
    }

    std::string s;
};

然后我创建了这个派生类:

manager get()
{
    return manager();
}

我能够创建该类的实例并将其返回:

def Gaussian(sigma, x, mu):
    p = 1/(sigma*np.sqrt(2*np.pi))*np.exp(-(x-mu)**2/(2*sigma**2))
    return p

N = 10
i = 0
x[0] = 0.5
results = []

for i in range (0,N):
    y = x[i] + np.random.normal(0,0.01)
    H = Gaussian(1,y,1)/Gaussian(1,x[i],1)
    alpha = np.random.uniform(1,1)
    if H >= alpha:
        x[i+1]=y
        results.append(y)

print(results)

我认为这是不可能的,因为删除了复制构造函数并删除了隐式生成的移动构造函数,因为存在用户定义(已删除)的复制构造函数。

此代码使用MinGW-64 7.2进行编译,但不使用MSVC 2017进行编译,并收到此消息:

  

function" manager :: operator =(const manager&)throw()" (隐式声明)无法引用 - 它是一个已删除的函数

这是编译器的问题,C ++设计允许还是我做错了什么?

3 个答案:

答案 0 :(得分:6)

在C ++ 17中,此操作既不需要移动也不需要复制; the entire thing is elided

因此,Visual Studio在实现此语言标准时要错误或不完整。

一般来说,尽量不要改变C ++自己的语义。防止昂贵的东西很好,但防止免费的东西是IMO的一个步骤。

根据您的确切版本,this blog post可能相关 - 它表明他们试图使此功能正常工作,但它太破碎了,所以他们推出了它回到现在;我不知道是否有更新版本实现它。

答案 1 :(得分:4)

从C ++ 17开始,我们保证copy elision。这意味着从函数返回值不需要复制或移动。

不幸的是,Visual Studio doesn't yet support this

  

P0135R1保证复制省略号

答案 2 :(得分:3)

中,prvalue表达式不是逻辑对象。在中,它们在逻辑上是对象(或者更确切地说是对象)。

现在,prvalue表达式是关于如何制作对象的指令。在某些情况下,这些指令适用于创建临时或非临时对象。

这通常被称为“保证省略”。但实际上它在许多情况下(不是全部)都消除了对elision的任何需求。

manager get() {
  return manager();
}

manager()中是一个创建对象的prvalue表达式。返回值是另一个prvalue。这些具有其身份和生命周期合并的两个对象可以<{1}}复制或移动到manager()的返回值

get中是prvalue,manager()的返回值也是如此。您没有“复制”或“移动”有关如何创建对象的指令,也没有对象。返回只是告诉返回值“这里是你需要的指令”。

get()

这里我们从prvalue构建manager foo = get(); - 来自如何制作foo的说明。没有创建临时对象;相反,我们只是按照manager的prvalue返回指示构造对象。

中我们会有一个临时管理器对象,其生命周期可以通过命名对象get()来消除。

这种省略和直接使用prvalues的效果在运行时非常相似,但其中一个涉及我们后来消除的逻辑移动或复制构造函数调用,另一个从未有过第二个对象开始。

为什么MSVC2017的行为不同,他们对的实施仍然不完整(每年都以较小的方式,但我仍然被烧伤),更不用说