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】:

这两行都非常好,从客户端代码的角度来看,最终会产生相同的可观察行为:priceCPrice 类型的默认构造变量,当然分配在堆栈上。


如果你想深入了解技术细节,它们是不一样的:

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++ 对象初始化(堆栈)的主要内容,如果未能解决你的问题,请参考以下文章

C++面试常错问题摘要

PHP对象在内存堆栈中的分配

PHP对象在内存堆栈中的分配

C++中变量声明的区别

在 C++ 中初始化对象之前声明一个对象

C++ 中构造函数的对象初始化问题[关闭]