为什么编译器会在这个问题上困扰我?

发布于 2024-12-13 04:40:41 字数 943 浏览 0 评论 0原文

(使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

别低头,皇冠会掉 2024-12-20 04:40:41

这种类型的初始化称为复制初始化。我相信 C++11 标准中的以下条款适用于此(第 8.5.16 段,第 204 页):

如果初始化是直接初始化,或者如果是
复制初始化,其中源的 cv 不合格版本
type 是与该类相同的类,或者是该类的派生类
目的地,构造函数被考虑。适用的构造函数
被枚举(13.3.1.3),并通过重载选择最好的一个
决议(13.3)。调用如此选择的构造函数来初始化
对象,以初始化表达式或表达式列表作为其
参数。如果没有构造函数适用,或者重载决策是
不明确,初始化格式错误。

在这种情况下,最适用的构造函数是复制构造函数,它是私有的,因此会出现错误消息。

为了进一步回答您的问题,当复制者是私有的时,由于标准强加的规则,您的程序根本不允许通过编译器检查。当您将复制向量公开时,程序将变得有效,但对复制向量的调用将被优化掉。

编辑:
好的,详细说明上一段。您在这里处理的是所谓的复制省略。虽然在这种情况下可以进行复制省略,但该标准要求您为您的类提供一个可访问的复制构造函数。

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):

If the initialization is direct-initialization, or if it is
copy-initialization where the cv-unqualified version of the source
type is the same class as, or a derived class of, the class of the
destination, constructors are considered. The applicable constructors
are enumerated (13.3.1.3), and the best one is chosen through overload
resolution (13.3). The constructor so selected is called to initialize
the object, with the initializer expression or expression-list as its
argument(s). If no constructor applies, or the overload resolution is
ambiguous, the initialization is ill-formed.

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.

不爱素颜 2024-12-20 04:40:41
exampleClass e1=exampleClass();

这将首先使用默认构造函数创建一个临时 exampleClass,然后使用复制构造函数将其复制到 e1 中。这将调用私有复制构造函数,从而给出错误。使用默认构造函数实例化类实例的正确方法是:

exampleClass e1;
exampleClass e1=exampleClass();

This will first create a temporary exampleClass using the default constructor and then copy that into e1 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:

exampleClass e1;
靑春怀旧 2024-12-20 04:40:41

编译器需要在那里bug你。虽然可以省略副本,但标准要求复制构造函数对于该类型的构造是可访问的。当然,您可以简化代码并完全避免复制构造:

exampleClass e1; // Will call exampleClass::exampleClass()

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:

exampleClass e1; // Will call exampleClass::exampleClass()
决绝 2024-12-20 04:40:41
exampleClass e1=exampleClass();

与以下内容相同:

exampleClass e1(exampleClass());

即它调用(私有)复制构造函数。

exampleClass e1=exampleClass();

is the same as:

exampleClass e1(exampleClass());

i.e it invokes the (private) copy constructor.

手心的海 2024-12-20 04:40:41

这是因为在编译时,编译器会检查用户尝试访问的函数是否确实可以访问。因此,当您使用 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.

你在我安 2024-12-20 04:40:41

每个人都解释了如何实例化一个对象,@Grigory Javadyan 在复制省略方面提出了很好的观点。看起来,MSVC 即使在调试模式下也会进行这种优化(所谓的返回值优化)。

exampleClass e1=exampleClass();

与您将看到的相同,

exampleClass giveExample()
{
  return exampleClass();
}

exampleClass e1 = giveExample();

不会调用复制构造函数。

但在这里:

exampleClass giveExample()
{
  exampleClass example;
  return example;
}

exampleClass e1 = giveExample();

您将看到另一条输出行:

in the copy ctor

因为您强制编译器首先生成一个对象,然后返回它。

此处此处这里我可以找到一些与您类似的问题。

附言。 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.

exampleClass e1=exampleClass();

is the same as

exampleClass giveExample()
{
  return exampleClass();
}

exampleClass e1 = giveExample();

You will see that copy ctor will not be called.

But here :

exampleClass giveExample()
{
  exampleClass example;
  return example;
}

exampleClass e1 = giveExample();

you will see another output line :

in the copy ctor

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.

伴我老 2024-12-20 04:40:41

这不是在 C++ 中实例化对象的方式。如果你希望它在堆栈上分配,你可以写:

exampleClass e1;

然后你就完成了,因为 exampleClass 的构造函数不接受任何参数。

否则,如果您希望将其分配在堆上,您可以这样写:

exampleClass e1 = new exampleClass(); 

您编写的方式实际上创建了一个临时对象,并调用该临时对象上的复制构造函数来创建 e1。问题是您的复制因子是私有的,因此编译器会显示错误消息。

That's not how you do instantiate an object in C++. If you want it allocated on the stack, you write:

exampleClass e1;

and you're done, sincee exampleClass' constructor accepts no parameters.

Otherwise, if you want it allocated on the heap, you write:

exampleClass e1 = new exampleClass(); 

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.

影子是时光的心 2024-12-20 04:40:41

当你编写

exampleClass e1 = exampleClass() 

编写相同。

exampleClass e1( exampleClass() );

它时,它与调用复制向量的

when you write

exampleClass e1 = exampleClass() 

it is the same as writing

exampleClass e1( exampleClass() );

which invokes the copy ctor.

灯角 2024-12-20 04:40:41

这是因为复制构造函数是私有的..

您的代码正在

  • 创建一个临时 exampleClass 并调用默认构造函数 exampleClass()
  • 尝试使用私有复制构造函数将生成的临时对象分配给 e1

Its because the copy constructor is private..

your code is

  • creating a temporary exampleClass and invoking the default constructor exampleClass()
  • attempting to assign the resulting temporary object to e1 using the private copy constructor
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文