C++构造函数调用顺序

Mar*_*ger 3 c++ constructor copy-constructor

当我初始化我的类的对象时,默认和复制构造函数都被调用.

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;
}
Run Code Online (Sandbox Code Playgroud)

结果:

default
copy

default

A (int n)

A (string s, int n)
copy

A (int n2, string s2)
copy

为什么要做a_1,a_3a_4通话双方的默认和拷贝构造函数?A_3也有一个参数,但它不需要复制构造函数.

Joh*_*ica 6

要避免多余的复制构造函数调用,请删除=并使用此语法直接调用所需的构造函数:

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");
Run Code Online (Sandbox Code Playgroud)


Alo*_*ave 5

A_1 = A("con 1");

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

@David在他的评论中建议:不能因为隐式转换而忽略
副本,而是因为转换是显式的.也就是说,编译器无法对其进行优化,因为代码明确请求创建临时和复制结构.

但是,@ David和Me都无法通过标准引文来证实它.

A_2 ="con 2";

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

A a_3 = A(4);

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

a a_4 = A("a_4",10);

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

a_5 = A(11,"a_5");

通过调用构造函数构造临时对象,该构造函数将整数和字符串作为参数,然后使用此临时对象复制构造新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");
Run Code Online (Sandbox Code Playgroud)

我的初步答案是尝试解释行为,但是当我在Ideone上的gcc-4.3.4上编译它时,我发现gcc足够智能以优化复制构造函数调用.没有一个案例调用复制构造函数.

我得出的结论是,每个编译器根据其智能可以或不能优化复制构造函数调用,例如,虽然标准不要求编译器执行此类优化,但每个编译器根据其能力评估这些表达式.

如果我错了,请免费为我添加推理评论.

  • 第一种情况是最糟糕的,副本不能因为*implicit*转换而被省略,而是因为转换是*explicit*.也就是说,编译器无法对其进行优化,因为代码*明确地*请求创建临时和复制结构.将它与第二种情况进行比较,其中转换实际上是*隐式*并且编译器将其优化掉.1中的实际顺序是:从文字转换为字符串,从字符串构造临时,最后是复制构造.您的描述缺少中间步骤 (2认同)