在堆栈上声明对象的两种方式之间的差异

Difference between two ways of declaring an object on the stack

本文关键字:方式 之间 两种 声明 对象 堆栈      更新时间:2023-10-16

假设我没有在Beatle类中指定复制构造函数和operator=,下面两个声明的区别是什么?

Beatle john(paul);

Beatle john = paul;

编辑:

在对象赋值中,操作符=隐式调用复制构造函数,除非另有说明。

它们是不同的语法结构。第一个是直接初始化,第二个是复制初始化。它们的行为几乎相同,只是后者需要非explicit构造函数。*

都与赋值操作符无关,因为两行都是初始化

换句话说:const int i = 4;没问题,但const int i; i = 4;不行。

*)更准确地说:如果相关构造函数声明为explicit,则第二个版本不起作用。因此,更一般地说,直接初始化为您提供了一个"自由"转换:

struct Foo { Foo(std::string) {} };
Foo x("abc");  // OK: char(&)[4] -> const char * -> std::string -> Foo
Foo y = "abd"; // Error: no one-step implicit conversion of UDTs

要理解赋值操作符,只需将其分成几个部分。假设Foo有明显的operator=(const Foo & rhs)。我们可以说x = y;,它只是直接调用运算符,rhsy。现在考虑这个:
x = "abc";              // error, no one-step implicit conversion
x = std::string("abc"); // fine, uses Foo(std::string), then copy
x = Foo("abc");         // fine, implicit char(&)[4] -> const char* -> std::string, then as above

第一个是直接初始化&第二个是拷贝初始化。

直接初始化意味着使用单个(可能是转换)构造函数初始化对象,相当于形式T t(u);:

U u;
T t1(u); // calls T::T( U& ) or similar

复制初始化表示在必要时首先调用用户定义的转换之后,使用复制构造函数初始化对象,相当于形式T t = u;:

T t2 = t1;  // same type: calls T::T( T& ) or similar
T t3 = u;   // different type: calls T::T( T(u) )
            //  or T::T( u.operator T() ) or similar

如果构造函数声明为explicit,则复制初始化不起作用。

引用:
这个条目在Herb Sutter的GOTW中应该是一个很好的阅读。


回答您的编辑问题:
=在不同的用法中有不同的含义。

如果=用于同时创建和初始化对象的表达式中,则=不被视为赋值操作符,而被视为复制初始化操作符。

如果使用=将一个对象赋值给另一个对象,在对象创建后,将导致调用赋值操作符。