2011-10-22 95 views
3

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

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也有一个参数,但它不需要拷贝构造函数。

+0

为什么要添加一个默认构造函数? – curiousguy

+0

@curiousguy:我想在这里更清楚地描述问题。我可以这样做:'A(){cout <<“default”<< endl; }并将当前的默认构造函数改为:A(string s){str = string(s);} cout <<“A(string s)”<< endl; }'得到更好的调试信息。此外,如果您将'Foo()'设为私有,则此构造函数在类之外变为不可用。然后,有'显式'关键字,做我不记得:) AFAIK就是这样。 –

+0

@MartinBerger请在你的问题中编辑“_Why是A_1 calling default_”。 – curiousguy

回答

5

甲A_1 = A( “CON 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对象。

请注意,您没有为您的类定义的Default构造函数。

您可以通过避免创建临时对象,并通过不使用赋值(=)在上述情况下复制构造对象来以更高效的方式实现相同效果。

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

我最初的答案是在试图解释的行为,而是因为我编译这对GCC-4.3.4 Ideone,我发现,海湾合作委员会有足够的智能来优化拷贝构造函数调用。没有任何情况调用复制构造函数。

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

如果我对此有误,请随意给我加推理评论。

+1

这是错误的。 'a_3'没有复制结构; OP在问为什么会出现这种情况,因为在所有其他情况下复制结构都会发生。 – Gorpik

+0

@Gorpik:谢谢correct.Got有点带走了cntrl + c cntrl + v :) –

+0

@Als:案例a_1:但即使我有这样的构造:'A(字符串S){字符串=字符串(S) ; cout <<“A(string s)”<< endl; }'并使用这一行:'A a_7 = A(string(“a_7”));'复制构造函数被调用。并没有隐式类型转换。为什么是这样?编译器有足够的构造函数来优化。 –

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"); 
+0

这里没有默认的构造函数调用。 – curiousguy

+0

顺便说一句,“_这种直接调用所需构造函数的语法”被称为** direct ** - 初始化。 – curiousguy

0

原因是您正在进行隐式转换。当您构造a_1时,您使用的是const char*,它被隐式转换为std::string,该文件被送入A构造函数,然后复制构造函数。在构造a_3时,不涉及隐式转换,因此编译器可以跳过复制构造函数并直接使用int构造a_3

+0

好的。感谢你在Als的岗位上贡献了自己的力量。 +1 –

+0

你可以请备份这个答案吗? – curiousguy

+0

@curiousguy:我认为标准没有明确禁止在情况3中跳过复制构造函数;但它禁止链接两个隐式转换。这个禁止允许一些代理类正常工作。编译器可能很难知道是否跳过复制构造函数会导致违反禁止规定,所以它不会这样做。 – Gorpik

-6

简短回答

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

或者得到另一个编译器。

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

详细的解答

显示

1)编译器的行为是不一致的

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

3),因此,最好的非的答案是不会浪费太多时间试图弄清楚为什么编译器的行为是不一致的

4)如果优化是很重要的哟ü,开关编译器