C++实例化初始化语法

14

假设有这样一个类:

class Foo {
public:
    Foo(int);

    Foo(const Foo&);

    Foo& operator=(int);

private:
    // ...
};

这两行代码是完全等价的,还是存在微小的差异?

Foo f(42);

Foo f = 42;
编辑:我在原来的问题中使Foo构造函数“explicit”,混淆了问题。我已经删除了它,但感谢回答。
我还添加了一个复制构造函数的声明,以明确复制可能不是一个简单的操作。
我真正想知道的是,根据C++标准,“Foo f=42”会直接调用Foo(int)构造函数,还是复制构造函数会被调用?
看起来fasih.ahmed给出了我要找的答案(除非它是错误的)。
2个回答

21
class Foo {
public:
    Foo(explicit int);

    Foo& operator=(int);
};

那是无效的。语法应该是

class Foo {
public:
    explicit Foo(int);

    Foo& operator=(int);
};

区别在于,当您在其前面加上explicit时,转换构造函数不能用于隐式转换:
Foo f(10); // works
Foo f = 10; // doesn't work

以上内容与您在那里声明的赋值运算符无关。由于这是初始化(仅使用构造函数),因此不会使用它。以下内容将使用赋值运算符:

Foo f;
f = 10;

将使用Foo的默认构造函数(不带参数的构造函数)。


编辑:提问者更改了问题,询问特定方式是否可以。

Foo f = 1; // called "copy initialization" 
Foo f(1);  // called "direct initialization"

这两个表达方式意思相同,可以等价于以下内容:

Foo f(Foo(1));
Foo f(1);

如果接受 int 的转换构造函数未声明为关键字 explicit,则第一个是编译器错误(请参见上文)。如果所有语义约束仍然得到满足,甚至包括具有副作用的复制构造函数,则编译器允许在第一种情况下省略(优化掉)传递给 Foo 的复制构造函数的临时对象。这特别包括可见的复制构造函数。

这就是我试图解释的。我想我失败了。 - fasih.rana
抱歉,我在问题中不是故意加上“explicit”的。我已经更新了它。 - Kristopher Johnson
我仍然不认为我会删除我的答案的那一部分。底部的部分回答了你的作业操作的目的。 - Johannes Schaub - litb
感谢详细的解释。就像“即使复制构造函数具有副作用,编译器也允许省略...”这样的规则有时会让我讨厌C++。我的意思是,他们怎么可能让它更加混乱和潜在地造成损害呢? - j_random_hacker
j_random_hacker,我认为这是因为拷贝构造函数用于复制实例。如果没有必要复制,为什么还要进行拷贝呢?无论如何,拷贝构造函数不应该改变任何全局状态(它只应该初始化*this)。我认为允许编译器不进行拷贝是合理的。 - Johannes Schaub - litb
Foo f(10); // 可以工作 Foo f = Foo(10); // 这是正确的方式。 - benlong

9
Foo f = 42;

这个语句将会为值 '42' 创建一个临时对象。

Foo f(42);

这个语句会直接赋值,因此少了一个函数调用。


1
就我所知,我比较关心语句的形式等价或非等价性,而不是“创建相同的代码”。 - Kristopher Johnson
尽管它优化临时变量,它仍然具有优化的能力。 - Johannes Schaub - litb
在任何符合标准的编译器中,Foo f = 42 等同于 Foo f (Foo(42))。如果在编译调用时没有可用的复制构造函数实现,则无法进行优化,因为构造函数可能具有副作用。 - Gorpik
1
抱歉,之前的评论有误。根据标准,即使复制构造函数的实现不可用,编译器也可以进行优化。因此,如果构造函数确实具有副作用,则调用有些未定义。 - Gorpik
Gorphik,这不是副作用的问题。即使存在副作用,复制仍然可以省略。重点在于复制构造函数的可见性,如果复制构造函数不可见,则编译器不能省略复制。 - Johannes Schaub - litb
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接