C++ 对象初始化(堆栈)
Posted
技术标签:
【中文标题】C++ 对象初始化(堆栈)【英文标题】:C++ Object Initialization (Stack) 【发布时间】:2015-08-28 13:37:19 【问题描述】:今天看到一个我不熟悉的类的c++初始化。
CPrice price = CPrice();
初始化通常应该是这样的
CPrice price;
我会猜到第一个应该抛出错误或其他东西。
这里会发生什么?我猜该变量在堆栈上,因为它没有用 new
初始化。
我将 Visual Studio Express 2012 与 Microsoft C++ 编译器一起使用。这可能是微软编译器特定的东西,因此是允许的吗?
【问题讨论】:
我认为他们正在遵循某种风格指南。如果您在创建变量时有=
,则您知道它已被初始化。
为什么你认为这会产生错误? CPrice()
是一个构造函数,它返回一个分配给新声明的变量的对象...
@tobi303 是用 = 赋值还是复制(“operator=”)?
这是一个初始化;这里没有作业。
@Bongo 不,实际上在变量声明的上下文中=
表示复制。 CPrice price = CPrice();
和 CPrice price(CPrice());
在定义上是相同的。欢迎来到 C++ 语法怪癖。
【参考方案1】:
这两行都非常好,从客户端代码的角度来看,最终会产生相同的可观察行为:price
是CPrice
类型的默认构造变量,当然分配在堆栈上。
如果你想深入了解技术细节,它们是不一样的:
CPrice price;
是price
类型为CPrice
的变量的默认初始化。这是一个用户类型(即一个类),所以它总是意味着调用默认构造函数。
CPrice price = CPrice();
是一个复合表达式,它做了两件事:
CPrice()
:通过直接初始化(它调用带有()
的构造函数)初始化和匿名CPrice
对象(在堆栈上)。由于括号为空,这将调用默认构造函数。
然后它复制初始化(在 C++11 之前)/移动初始化(可用于 C++11 以后)类型为 CPrice
的变量 price
,复制自/移动自对象是匿名 @ 987654334@ 实例。
最长的分配强制CPrice
存在复制构造函数,否则代码将出错。但是允许编译器跳过复制构造并对其进行优化,方法是发出与最短形式相同的代码。
此外,在 C++11 中,如果存在针对 CPrice
的移动构造函数,则在这种情况下将使用它来代替复制构造函数(也就是说,如果无论如何都没有完全删除此操作)。
因此,唯一可察觉的区别是,即使CPrice
不是可复制构造的,最短的形式也会编译。这两种形式都要求CPrice
是默认可构造的。
一个或多或少相关的精度,来自另一个答案。你可以认为像这样的假设的中间立场声明是一样的:
CPrice price();
然而,它实际上完全不同:这个声明 price
是一个不带参数的函数(空括号),并返回一个 CPrice
。它被通俗地称为最令人头疼的解析。
【讨论】:
副本很可能会被省略,并且与第二个示例相同。 @NathanOliver 即使副本被省略(我同意它几乎肯定会),相关的复制构造函数也必须存在并且可以调用,所以它并不完全相同。 感谢您的 cmets ! @NathanOliver:我想我们是同时写的; ) 在 C++11 中,CPrice price = CPrice();
price
可以被移动构造,参见here how move constructor is generated by default。
这方面有一篇很棒的 Herb Sutter GOTW 文章。你已经涵盖了他在那里提到的几乎所有内容,尽管对于任何对此主题感到困惑的人来说仍然值得一读:herbsutter.com/2013/05/09/gotw-1-solution【参考方案2】:
当实例已经被声明时,赋值正在调用赋值运算符(如果没有删除)。第一行声明 AND 显式调用构造函数,这对堆栈并没有真正的帮助,但更多的是在具有多态性的堆中。 第二行直接调用它的默认构造函数(如果没有删除并且也没有实现 operator())
如果您仍然想知道运算符 = ,请在类声明中显式声明CPrice & operator = (const CPrice &) = delete;
【讨论】:
" heap with polymorphism" 实例的存储与多态有什么关系??【参考方案3】:这两行的作用完全相同。它们都调用默认构造函数(一个没有参数的构造函数)。同样有效的可能是CPrice price();
,因为如果有一个构造函数接受它们,那么这个和你拥有的第一个允许你推送参数,而你的第二个不会。同样是的,如果没有使用 new 关键字,那么分配是在堆栈上(对于像这样的简单事情)。
【讨论】:
“像这样的简单事情”是什么意思? 只是简单的对象创建。在我看来,在 C++ 中可以通过三种方式来处理所有事情,所以我基本上是在掩饰自己,以防有人过来告诉我 new 并不是在堆上创建新对象的唯一方法。CPrice price();
没有做你认为它做的事情:它是一个名为 price
的函数的声明,它不接受任何参数并返回一个 CPrice
对象。请参阅most vexing parse 上的文章。
“这两行的作用完全相同。” 不,它们没有。它们有不同的含义,尽管允许编译器优化第二个,以有效地相同。 CPrice price = CPrice();
和CPrice price(CPrice());
定义相同,CPrice price;
原理不同。
那么我今天学到了一些新东西。我是否认为最终结果是相同的?以上是关于C++ 对象初始化(堆栈)的主要内容,如果未能解决你的问题,请参考以下文章