我正在阅读直接初始化和复制初始化(第8.5/12节)之间的区别:

T x(a);  //direct-initialization
T y = a; //copy-initialization

通过阅读有关copy-initialization的内容,我了解到它需要accessible & non-explicit copy-constructor,否则该程序将无法编译。我通过编写以下代码进行了验证:
struct A
{
   int i;
       A(int i) : i(i) { std::cout << " A(int i)" << std::endl; }
   private:
       A(const A &a)  {  std::cout << " A(const A &)" << std::endl; }
};

int main() {
        A a = 10; //error - copy-ctor is private!
}

GCC给出了一个错误(ideone):



到目前为止,一切都很好,reaffirming what Herb Sutter says



之后,通过注释private关键字使copy-ctor可以访问。现在,我自然希望可以打印出以下内容:



但令我惊讶的是,它改为打印以下内容(ideone):



为什么?

好吧,我知道,首先使用A10类型的int中创建一个A(int i)类型的临时对象,并根据需要在此处应用转换规则(第8.5/14节),然后应该调用copy- ctor初始化a。但事实并非如此。为什么?

如果允许某个实现消除对调用copy-constructor的需求(第8.5/14节),那么为什么在将copy-constructor声明为private时为何不接受代码?毕竟,它没有调用它。它就像一个被宠坏的 child ,先是恼人地要求一个特定的玩具,当您给他一个特定的玩具时,他会把它扔到您的背后。 :|

这种行为会危险吗?我的意思是,我可能会在copy-ctor中做一些其他有用的事情,但是如果不调用它,那么它不会改变程序的行为吗?

最佳答案

您是在问为什么编译器要进行访问检查吗?在C++ 03中为12.8/14:



当实现“省略复制构造”(允许12.8/15允许)时,我不认为这意味着复制ctor不再“隐式使用”,只是不再执行。

还是您在问为什么标准这么说?如果复制省略是关于访问检查的此规则的异常(exception),则您的程序在成功执行省略的实现中将采用正确的格式,而在没有执行的实现中则采用不正确的格式。

我很确定作者会认为这是一件坏事。当然,以这种方式编写可移植的代码会更容易-编译器会告诉您是否编写了尝试复制不可复制对象的代码,即使该复制碰巧在实现中被删除。我怀疑这也可能给实现者带来不便,尽管在不知道是否值得考虑的情况下,在检查访问之前确定优化是否成功(或将访问检查推迟到尝试进行优化之后)。



当然,这可能很危险-当且仅当对象实际被复制时,复制构造函数才会出现副作用,您应该相应地对其进行设计:标准指出复制可以被删除,因此除非将代码放入复制构造函数中,否则您很高兴在12.8/15中定义的条件下消除它:

MyObject(const MyObject &other) {
    std::cout << "copy " << (void*)(&other) << " to " << (void*)this << "\n"; // OK
    std::cout << "object returned from function\n"; // dangerous: if the copy is
      // elided then an object will be returned but you won't see the message.
}

07-24 09:46
查看更多