使用带有新运算符的列表初始化



Background

请考虑以下代码片段:

MyClass * p1 = new MyClass;
p1->data = 1;
MyClass c2 = MyClass();
p2.data = 2;
new(p1) MyClass {c2};
cout << p1.data;

其中MyClass仅包含单个公共成员int data

前 4 行很简单:我们创建两个 MyClass 对象,一个使用new,一个不使用。下一行发生的情况是c2的内容被复制到p1中,这意味着最后一行的输出是2

我的问题是关于线路上到底发生了什么new(p1) MyClass {c2};.我的理解是有两个操作:new和列表初始值设定项。对于new,基于此,如果您使用指针作为参数调用new,它不会分配任何新内存,而只是在给定指针的位置构造一个对象,指针是new运算符的返回值。这意味着new(p1) MyClass解析为指向与p1相同的地址的指针。然后,使用列表初始化{c2}将内容设置为p1c2,这就是为什么末尾的输出是2而不是1的原因。

问题:

这是对正在发生的事情的正确理解吗?

如果是这样,我有一个困惑点是new运算符new(p1) MyClass解析为指针,但看起来我们正在为它分配c2,这不是一个指针,而是一个完整的MyClass对象。这是怎么回事?

最后,我想知道使用这种语法背后的动机是什么。我是来自 C 的C++新手,在 C 中,您只需编写类似*p1 = c2;的东西来完成与new(p1) MyClass {c2};相同的事情

您提出的问题包含多种成分。主要的两件事是

  • 3 法则(如果将移动语义与现代 c++ 一起包括在内,则为 Big 5)
  • 内存管理

首先,当您使用new关键字时,它用于通过分配内存然后构造它在免费存储/堆区域中创建一个对象。即使在程序终止后,此处创建的对象仍保留在此处,并且必须使用关键字delete将其删除。 使用此逻辑,p1对象存储在免费存储中。

就你第五行的前半部分而言

new(p1) 

new 的这种用法不会分配内存,但实际上确实在p1的位置构造对象。

下半场...

MyClass {c2};

负责调用对象的构造函数并根据 c2 的属性构造所述对象(也称为复制构造函数)。 举个很好的例子,下面是 c++ 中新运算符的文档链接:http://www.cplusplus.com/reference/new/operator%20new/

复制构造函数的这个想法是3 法则的一部分,如下所示:

  • 析构函数(用于销毁对象的函数)
  • 复制构造函数(第 5 行中用于创建新对象的内容)
  • 复制赋值运算符(重载 = 运算符以创建新函数,即 Obj1 = Obj 2)。

我建议研究这些概念,以进一步了解C++中的对象行为。其中大多数已经为 C++ 中的所有对象预定义。但是,您始终可以覆盖其中任何一个以满足您的对象需求。

重要提示:如果您覆盖C++为您提供的默认 3 大中的任何一个,则必须覆盖所有这些,因为可能存在差异。 这里有一个很好的幻灯片,可以帮助您深入研究 Big 5 的主题(另外两个与现代C++中的语义有关,但前三个幻灯片主题详细介绍了 Big 3):https://www.feabhas.com/sites/default/files/2016-06/Rule%20of%20the%20Big%20Five.pdf

最新更新