在堆栈上声明对象的两种方式之间的区别
Posted
技术标签:
【中文标题】在堆栈上声明对象的两种方式之间的区别【英文标题】:Difference between two ways of declaring an object on the stack 【发布时间】:2012-01-01 22:49:59 【问题描述】:假设我在Beatle
类中没有指定复制构造函数和operator=
,下面两个声明有什么区别?
Beatle john(paul);
和
Beatle john = paul;
编辑:
在对象赋值中,运算符=
隐式调用复制构造函数,除非另有说明?
【问题讨论】:
为什么选择john
和paul
作为变量名,Dog
作为类型?
@Nawaz 叫约翰和保罗的狗怎么了?
@JohannesSchaub-litb: 对或错,直到现在我还没有说过那样的话。我只是好奇为什么他选择了那个。
【参考方案1】:
它们是不同的语法结构。第一个是直接初始化,第二个是复制初始化。它们的行为几乎相同,只是第二个需要非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;
,它只是直接调用运算符,rhs
是y
。现在考虑一下:
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
【讨论】:
您能提供参考吗? (我只是好奇...) @xmoex:全部在第 8.5 节中。【参考方案2】:首先是直接初始化,其次是复制初始化。
直接初始化表示使用单个(可能是转换)构造函数初始化对象,等效于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
,则复制初始化不起作用。
参考:This Herb Sutter 的 GOTW 中的条目应该是一本好书。
回答您已编辑的问题:=
根据使用方式的不同而具有不同的含义。
如果=
用于同时创建和初始化对象的表达式中,则=
不被视为赋值运算符,而是被视为复制初始化。
如果使用=
将一个对象分配给另一个对象,在创建该对象之后,它会调用赋值运算符。
【讨论】:
那么就是说Beatle john(paul);
和Beatle john = paul:
是等价的?
@LeifEricson:嗯?答案说明,它们是如何不等效的,答案的哪一部分对您来说不清楚或让您感到困惑?
T t2 = t1; // same type: calls T::T( T& ) or similar
这意味着这行调用了一个复制构造函数,这意味着在这种情况下它们是等价的。以上是关于在堆栈上声明对象的两种方式之间的区别的主要内容,如果未能解决你的问题,请参考以下文章