C++ C++;构造函数调用顺序

C++ C++;构造函数调用顺序,c++,constructor,copy-constructor,C++,Constructor,Copy Constructor,初始化类的对象时,将同时调用default和copy构造函数 class A { public: A (string s) { str = string (s); cout << "default" << endl; } A (int n) { cout << "A (int n)" << endl; } A (string s, int n) { cout << "A (string s, int n)" <&

初始化类的对象时,将同时调用default和copy构造函数

class A
{
public:
   A (string s) { str = string (s); cout << "default" << endl; }
   A (int n) { cout << "A (int n)" << endl; }
   A (string s, int n) { cout << "A (string s, int n)" << endl; }
   A (int n2, string s2) { cout << "A (int n2, string s2)" << endl; }
   A (const A& a) { str = a.str; cout << "copy" << endl; }

   inline void printA () { cout << str << endl; }

   string str;
};


int main (void)
{
   A a_1 = A ("con 1");
   cout << endl;

   A a_2 = "con 2";
   cout << endl;

   A a_3 = A (4);

   A a_4 = A ("a_4", 10);
   cout << endl;

   A a_5 = A (11, "a_5");
   cout << endl;

   cin.get();
   return 0;
}
A类
{
公众:

A(string s){str=string(s);cout为了避免多余的复制构造函数调用,消除
=
并使用此语法直接调用所需的构造函数:

A a_1("con 1");
A a_2("con 2");
A a_3(4);
A a_4("a_4", 10);
A a_5(11, "a_5");
A A_1=A(“con 1”)

通过调用以字符串作为参数的构造函数来构造临时对象,因为传递的类型是
const char*
,编译器必须首先执行到
string
()的隐式转换,然后使用此临时对象复制构造新的
a_1
对象。
由于存在额外的隐式转换,编译器无法对此进行优化,需要调用复制构造函数。
根据评论和进一步的研究,我怀疑(上面斜体)的推理是否正确

@大卫在评论中建议:
不能忽略副本,不是因为隐式转换,而是因为转换是显式的。也就是说,编译器无法优化它,因为代码显式请求创建临时和副本构造

然而,@David和我都无法通过标准引用来证实这一点

A A_2=“con 2”

通过调用以字符串作为参数的适当构造函数来构造对象
a2

A_3=A(4)

案例1中的注释也适用于此处:
理想情况下,应该通过调用以整数为参数的构造函数来构造一个临时对象,然后使用此临时对象复制一个新的
a_3
对象,如案例1所示,但编译器可以通过调用以整数为参数的构造函数来优化并直接构造该对象

A A_4=A(“A_4”,10)

通过调用构造函数构造一个临时对象,该构造函数将字符串和整数作为参数,然后使用此临时对象复制并构造一个新的
a_4
对象

A A_5=A(11,“A_5”)

通过调用构造函数构造一个临时对象,该构造函数将整数和字符串作为参数,然后使用此临时对象复制并构造一个新的
a_5
对象

请注意,您没有为类定义默认构造函数

在上述情况下,您可以通过不使用赋值(
=
)来避免创建临时对象,然后复制并构造对象,从而以更高效的方式实现这一点


我最初的回答是试图解释这种行为,但当我在上的gcc-4.3.4上编译时,我发现gcc足够智能,可以优化复制构造函数调用。没有一种情况会调用复制构造函数

我得出的结论是,在这种情况下,每个编译器根据其智能可以或不能优化复制构造函数调用,而标准不要求编译器执行此类优化。每个编译器根据其功能计算此类表达式


如果我在这一点上错了,请随意给我添加一条带有推理的注释。

原因是您正在进行隐式转换。当您构造
a_1
时,您使用的是
const char*
,它隐式转换为
std::string
,该字符串被送入
a
构造函数,然后复制con结构化。当您构造
a_3
时,不涉及隐式转换,因此允许编译器跳过复制构造函数,直接用
int
简短答案构造
a_3
这里没有人知道。你应该问问编译器编写人员。

或者找另一个编译器

这种不一致的行为没有根本原因

详细答案 1) 显示的编译器行为不一致

2) 只有编译器作者才能回答为什么编译器行为不一致的问题——甚至可能他也不能,您需要浏览源代码

3) 因此,最好的答案是不要浪费太多时间试图找出编译器行为不一致的原因


4) 如果优化对您很重要,请切换编译器这是错误的。
a_3
;OP会问为什么会出现这种情况,因为复制构造在所有其他情况下都会发生。@Gorpik:谢谢更正。对cntrl+c cntrl+v:)有点忘乎所以。@MartinBerger编译器也没有任何要求第一种情况最糟糕,不能忽略副本,不是因为隐式转换,而是因为转换是显式的。也就是说,编译器不能优化它,因为代码显式地请求创建临时和副本构造。将其与第二种情况进行比较,其中sion实际上是隐式的,编译器会对其进行优化。1中的实际顺序是:从文字到字符串的转换,从字符串到临时结构的构造,最后是复制结构。您的描述缺少中间结构step@DavidRodríguez dribeas:感谢您的详细阐述,标准r制定了哪些规则考虑到这一点,我相信编译器可以根据自己的能力进行优化,因为gcc(Ideone link in answer)只是优化了所有的复制构造函数调用,而msvc2010作为OP声明提供了上述输出。好的。感谢您在Als帖子中的贡献。+1您能支持这个答案吗?@curiousguy:我认为标准没有明确禁止在案例3中跳过复制构造函数;但它禁止链接两个隐式转换。此禁止允许某些代理类正常工作。编译器可能很难知道跳过复制构造函数是否会导致违反该禁止
A a_1("con 1");
A a_2("con 2");
A a_3(4);
A a_4("a_4", 10);
A a_5(11, "a_5");
A a_1("con 1");
A a_2("con 2");
A a_3(4);
A a_4("a_4", 10);
A a_5(11, "a_5");