当复制构造函数是私有的而未实现时,是否允许RVO?

时间:2012-04-24 08:25:46

标签: c++ copy-constructor rvo

假设我有一个类,其中复制构造函数是私有的,未实现(使对象不可复制)

class NonCopyable {
// whatever
 private:
    NonCopyable( const NonCopyable&);
    void operator=(const NonCopyable&);
 };

现在在同一个类的某个成员函数中,我编写了返回该类对象的代码:

NonCopyable NonCopyable::Something()
{
    return NonCopyable();
}

这是RVO可以启动的情况。

RVO仍然要求可以访问复制构造函数。由于对复制构造函数的可能调用是在同一个类成员函数中完成的,因此复制构造函数是可访问的。因此,尽管意图是禁止使用复制构造函数,但技术上可以使用RVO。

在这种情况下是否允许RVO?

4 个答案:

答案 0 :(得分:6)

是的,在这种情况下允许使用RVO - 至少如果Something()的来电者是班级成员或朋友。

我认为这就是为什么非可复制类的私有继承比你想要防止复制的每个类中“手动”更好的原因之一。在这种情况下,没有意外的漏洞。

例如,使用boost::noncopyable

class NonCopyable : private boost::noncopyable {
public:
    NonCopyable() {};
    NonCopyable Something();
};

NonCopyable NonCopyable::Something()
{
    return NonCopyable();  // causes compile time error, not link time error
}

答案 1 :(得分:4)

你的例子非常有趣。

这是典型的C ++ 03声明。

class NC {
public:
    NC NC::Something() {
        return NC();
    }

private:
    NC(NC const&);
    NC& operator=(NC const&);
};

如上所述,即使我们在语义上想要避免复制,RVO也可能会启动。

在C ++ 03中,解决方案是委派:

class NC: boost::noncopyable {
public:
    NC NC::Something() { // Error: no copy constructor
        return NC();
    }
};

在C ++ 11中,我们可以选择使用delete关键字:

class NC {
public:
    NC NC::Something() { // Error: deleted copy constructor
        return NC();
    }

private:
    NC(NC const&) = delete;
    NC& operator=(NC const&) = delete;
};

但有时,我们希望阻止复制,但希望允许 Builder (如模式中所示)。

在这种情况下,只要RVO启动,您的示例就会起作用,这有点令人讨厌,实际上是非标准的。应提供复制构造函数的定义,但您希望不使用它。

在C ++ 11中,删除复制操作和定义移动操作(甚至是私有)支持此用例。

答案 2 :(得分:0)

允许,但您可能会收到链接错误,因为未实现复制构造函数。 如果你为NonCopyable( const NonCopyable&)提供了一个正文,那就可以了。

答案 3 :(得分:0)

一个重点可能会掩盖实际问题。

  

如果允许RVO,这种功能的用例是什么?

可以通过3种方式调用此函数,其中2种将是编译器错误:

NonCopyable obj;
NonCopyable obj2 = obj; // 1 --> error
NonCopyable &r = obj;   // 2 --> error
const NonCopyable &rc = obj; // 3 --> ok, but dangerous (may lead to UB)

无法有效使用返回的对象,因此无论是否允许使用RVO都无关紧要。