2015-03-13 50 views
2

下面是一个简单的例子:一个变量声明创建了多个实例

class A { 
public: 
    A() { 
    printf("%p C1\n", this); 
    } 
    A(const char* p) { 
    printf("%p C2\n", this); 
    } 
}; 

int main(int argc, char *argv[]) { 
    A a; 
    a = "abc"; 
} 

在代码中,虽然A声明只有一次,也有越来越创建的A两个实例。构造函数被调用两次。我可以在VS 2013以及gnu C++中重现这一点。

想知道这是行为错误还是规范的一部分。

+0

您可以通过定义一个'A ::运算符=(为const char *)避免临时' (或者更好的'A :: operator =(std :: string const&)')。 – Walter 2015-03-13 16:56:22

+0

'想知道这个行为是否是一个错误'您使用了全世界数以千计的人和公司使用的两种编译器,并且从这些不重要的代码中获得了相同的结果。鉴于此,这是一个错误有什么机会? – PaulMcKenzie 2015-03-13 17:05:12

+0

@MatthewMoss我在评论最后的问题真的是讽刺。该程序是一个玩具程序,g ++和Visual Studio被成千上万的人使用。如果这是一个错误,它会在整个网络上报告(再加上两个独立的编译器厂商会用这样一个非常简单的程序产生相同的错误)。 – PaulMcKenzie 2015-03-13 17:38:51

回答

4

因为你还没有禁用自动生成的赋值运算符或拷贝构造函数,类实际上是这样的编译器:

class A { 
public: 
    A() { 
    printf("%p C1\n", this); 
    } 
    A(const A& rhs) { } 
    A(const char* p) { 
    printf("%p C2\n", this); 
    } 
    A& operator=(const A& rhs) { return *this; } 
}; 

所以a = "abc"被解释为a.operator=(A("abc"))

它需要一个const A&作为operator=的参数,它可以构造,因为您提供了构造函数A(const char*)

您可以通过显式构造函数来防止意外转换。

class A { 
public: 
    A() { 
    printf("%p C1\n", this); 
    } 
    explicit A(const char* p) { 
    printf("%p C2\n", this); 
    } 
}; 

那么这应该无法编译:

int main(int argc, char *argv[]) { 
    A a; 
    a = "abc"; 
} 

除非你明确构建:a = A("abc");

+0

'显式'的好处。 – 2015-03-13 16:59:44

+0

谢谢,@ChristianHackl。除非你非常清楚你正在做什么,否则将转换构造函数设为'explicit'是一个好习惯。也许甚至不是...... – 2015-03-13 17:00:55

6

它是规范的一部分。当你这样做:

a = "abc"; 

临时A对象被创建窗体上的RHS的​​表达式使用A(const char* p)构造。这用于为a赋值。

如果你这样做,而不是

A a = "abc"; 

你只看到一个构造函数调用。

+3

为了完整性,您可以重载'operator =(const char *)'来接管赋值,提供比创建临时对象更好的匹配。 – chris 2015-03-13 16:54:29