C ++构造函数调用顺序

时间:2011-10-22 15:17:12

标签: 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;
}

结果:

default
copy

default

A (int n)

A (string s, int n)
copy

A (int n2, string s2)
copy

为什么a_1a_3a_4同时调用默认和复制构造函数? A_3也有一个参数,但它不需要复制构造函数。

4 个答案:

答案 0 :(得分: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");

答案 1 :(得分:5)

  

A a_1 = A(“骗局1”);

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

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

然而,@ David和Me都无法通过标准引文来证实它。

  

A 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 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");

我的初步答案是尝试解释行为,但是当我在 Ideone 上的gcc-4.3.4上编译时,我发现gcc足够智能以优化复制构造函数call.None of cases调用复制构造函数。

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

如果我错了,请随意添加推文评论。

答案 2 :(得分:0)

原因是您正在进行隐式转换。在构造a_1时,您正在使用const char*,它会隐式转换为std::string,并将其输入A构造函数,然后复制构造。构造a_3时,不涉及隐式转换,因此允许编译器跳过复制构造函数并直接使用a_3构造int

答案 3 :(得分:-6)

简短回答

这里没有人知道。 你应该问编译器编写者。

或者获得另一个编译器。

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

详细答案

1)显示的编译器行为不一致

2)只有编译器作者可以回答这个问题为什么编译器行为不一致 - 甚至可能不是他,你需要浏览源代码

3)所以,最好的非答案是不要浪费太多时间来解决编译器行为不一致的原因

4)如果优化对您很重要,请切换编译器