我正在阅读直接初始化和复制初始化(第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):
为什么?
好吧,我知道,首先使用
A
从10
类型的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.
}