为什么编译器会在这个问题上困扰我?
(使用 Visual C++ 2010,在关闭优化的情况下在调试中进行编译)
我有以下非常简单的类:
class exampleClass
{
public:
exampleClass()
{
cout << "in the default ctor" << endl;
}
private:
exampleClass (const exampleClass& e)
{
cout << "in the copy ctor" << endl;
}
};
当我尝试使用以下 main 编译它时:
#include <iostream>
using namespace std;
int main()
{
exampleClass e1=exampleClass();
return 0;
}
我得到编译错误:
'exampleClass::exampleClass' : cannot access private
member declared in class 'exampleClass'
当我从复制构造函数中删除访问修饰符“private”时,程序编译并打印 only:
in the default ctor
为什么会发生这种情况?如果编译器无论如何都不会调用复制构造函数,为什么它会困扰我?
由于有些人错过了第一行(至少在某些编辑之前),我将重复一遍:
我在关闭优化的情况下在调试中编译。
(using Visual C++ 2010, compiling in debug with optimizations turned off)
I have the following very simple class:
class exampleClass
{
public:
exampleClass()
{
cout << "in the default ctor" << endl;
}
private:
exampleClass (const exampleClass& e)
{
cout << "in the copy ctor" << endl;
}
};
When I try to compile it with the following main:
#include <iostream>
using namespace std;
int main()
{
exampleClass e1=exampleClass();
return 0;
}
I get the compilation error:
'exampleClass::exampleClass' : cannot access private
member declared in class 'exampleClass'
When I remove the access modifier "private" from the copy ctor, the program compiles and prints only:
in the default ctor
Why is this happening? If the compiler will not invoke the copy ctor anyway, why is it bugging me?
Since some people missed the first line (at least before some edits) i will repeat it:
I compiled in debug with optimizations turned off.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
这种类型的初始化称为复制初始化。我相信 C++11 标准中的以下条款适用于此(第 8.5.16 段,第 204 页):
在这种情况下,最适用的构造函数是复制构造函数,它是私有的,因此会出现错误消息。
为了进一步回答您的问题,当复制者是私有的时,由于标准强加的规则,您的程序根本不允许通过编译器检查。当您将复制向量公开时,程序将变得有效,但对复制向量的调用将被优化掉。
编辑:
好的,详细说明上一段。您在这里处理的是所谓的复制省略。虽然在这种情况下可以进行复制省略,但该标准要求您为您的类提供一个可访问的复制构造函数。
This type of initialization is called copy-initialization. I believe the following clause from the C++11 standard applies here (paragraph 8.5.16, page 204):
In this case, the best applicable constructor is the copy ctor, which is private, hence the error message.
To further answer your question, when the copy ctor is private, your program is simply not allowed to pass the complier check because of the rules imposed by the standard. When you make the copy ctor public, the program becomes valid, but the call to the copy ctor is optimized away.
EDIT:
Okay, to elaborate on previous paragraph.You're dealing here with the so-called copy elision. While the copy elision is possible in this case, the standard requires you to provide an accessible copy ctor for your class.
这将首先使用默认构造函数创建一个临时
exampleClass
,然后使用复制构造函数将其复制到e1
中。这将调用私有复制构造函数,从而给出错误。使用默认构造函数实例化类实例的正确方法是:This will first create a temporary
exampleClass
using the default constructor and then copy that intoe1
using the copy constructor. This will invoke the private copy constructor and thus give you the error. The corrent way to instantiate an instance of a class with the default constructor is this:编译器需要在那里bug你。虽然可以省略副本,但标准要求复制构造函数对于该类型的构造是可访问的。当然,您可以简化代码并完全避免复制构造:
The compiler is required to bug you there. While the copy can be elided, the standard requires that the copy constructor is accessible for that type of construction. Of course, you can simplify the code and avoid the copy construction altogether:
与以下内容相同:
即它调用(私有)复制构造函数。
is the same as:
i.e it invokes the (private) copy constructor.
这是因为在编译时,编译器会检查用户尝试访问的函数是否确实可以访问。因此,当您使用 exampleClass e1=exampleClass(); 时,它首先检查复制构造函数是否可访问。它会抛出错误,因为复制构造函数不是私有的。 请记住,此时编译器尚未进入优化阶段,它会执行跳过复制构造函数的巧妙操作。
当您将复制构造函数公开时,编译器会成功地完成解析代码并确保所有内容都可访问且按顺序进行的阶段(实际上发生的事情不止如此),然后进入优化阶段,这通常是在“发布”模式下,它会做一些聪明的事情并绕过复制构造函数的使用。但是,如果您在“调试”模式下尝试相同的代码,您会看到复制构造函数确实被调用。
This is because at compile time, the compiler checks if the function the user is trying to access is really accessible. So when you use
exampleClass e1=exampleClass();
, it first checks if the copy-constructor is accessible. It spits out an error because the copy-constructor is not private. Remember that at this point the compiler hasn't gone onto the optimization stage where it does the clever stuff as to skip the copy-constructor.When you make the copy-constructor public, the compiler successfully goes through the stage of parsing the code and making sure that everything is accessible and is in order (there's actually more than that going on) and then at the optimization stage, which usually is on in 'Release' mode it does the clever stuff and by-passes the use of copy-constructor. However if you tried the same code in 'Debug' mode you'd see that the copy-constructor does get called.
每个人都解释了如何实例化一个对象,@Grigory Javadyan 在复制省略方面提出了很好的观点。看起来,MSVC 即使在调试模式下也会进行这种优化(所谓的返回值优化)。
与您将看到的相同,
不会调用复制构造函数。
但在这里:
您将看到另一条输出行:
因为您强制编译器首先生成一个对象,然后返回它。
此处,此处 和 这里我可以找到一些与您类似的问题。
附言。 Link#2 来自另一个问答网站。我希望这不是问题。
Everyone explains how you should instantiate an object and @Grigory Javadyan makes a good point on copy elision. It looks like, MSVC does this optimization (so called return value optimization) even in debug mode.
is the same as
You will see that copy ctor will not be called.
But here :
you will see another output line :
Because you are forcing the compiler to first generate an object and then return it.
Here, here and here some questions I can find, similar to yours.
PS. Link#2 is from another Q&A site. I hope this is not a problem.
这不是在 C++ 中实例化对象的方式。如果你希望它在堆栈上分配,你可以写:
然后你就完成了,因为 exampleClass 的构造函数不接受任何参数。
否则,如果您希望将其分配在堆上,您可以这样写:
您编写的方式实际上创建了一个临时对象,并调用该临时对象上的复制构造函数来创建 e1。问题是您的复制因子是私有的,因此编译器会显示错误消息。
That's not how you do instantiate an object in C++. If you want it allocated on the stack, you write:
and you're done, sincee exampleClass' constructor accepts no parameters.
Otherwise, if you want it allocated on the heap, you write:
The way you wrote it actually creates a temporary object and invokates the copy constructor on that temporary object to create e1. Problem is that your copy-ctor is private, so the compiler's error message.
当你编写
编写相同。
它时,它与调用复制向量的
when you write
it is the same as writing
which invokes the copy ctor.
这是因为复制构造函数是私有的..
您的代码正在
exampleClass()
Its because the copy constructor is private..
your code is
exampleClass()