在堆栈上声明对象的两种方式之间的区别

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;

编辑:

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

【问题讨论】:

为什么选择johnpaul作为变量名,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;,它只是直接调用运算符,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

【讨论】:

您能提供参考吗? (我只是好奇...) @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 这意味着这行调用了一个复制构造函数,这意味着在这种情况下它们是等价的。

以上是关于在堆栈上声明对象的两种方式之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

Java中实现多线程的两种方式之间的区别

函数声明的两种形式的区别

试图理解在 Java 中声明对象的不同方式? [复制]

函数——函数的两种声明方式:函数声明&函数表达式的区别(未完待续。。。)

JS中访问对象的两种方式区别

JS中访问对象的两种方式区别