在堆上构造对象是 C++ 语言中看似简单的任务。当代码
T* object = new T();
func(object);
被调用,我的理解是内存必须先分配,然后初始化,最后调用类的构造函数。此外,对象的虚拟表在构建完成之前不一定可用。
我的问题是:可以operator new
在对象完成构造之前返回指向已分配/初始化内存的指针,以便func(...)
对未完全构造的对象进行操作吗?这个问题的答案对我正在开发的多线程库有影响。
提前致谢。
在堆上构造对象是 C++ 语言中看似简单的任务。当代码
T* object = new T();
func(object);
被调用,我的理解是内存必须先分配,然后初始化,最后调用类的构造函数。此外,对象的虚拟表在构建完成之前不一定可用。
我的问题是:可以operator new
在对象完成构造之前返回指向已分配/初始化内存的指针,以便func(...)
对未完全构造的对象进行操作吗?这个问题的答案对我正在开发的多线程库有影响。
提前致谢。
operator new
分配内存。new
关键字(在示例代码中使用)用于operator new
分配内存,然后在该内存中构造对象。而且,是的,在没有适当同步的多线程应用程序中,指针值可以在构造函数的副作用发生之前在其他线程中变得可见。这是因为每个处理器都可以有一个单独的缓存,并且指针值可能会在构造函数副作用被读入缓存之前被读入缓存。阅读“双重检查锁定”以获取更多详细信息。
在object
构造之前不会指向对象。在new T()
完成之前不会返回。
我猜Pete Becker在缓存问题上是正确的......
我认为. operator new()
_T* object = new T();
object
如果我们非常简单地看待它(这只是为了说明的目的,并不是要精确定义 C++ 编译器实际上是如何做事的),我们可以分解T* object = new T();
为几个部分:
void *temp = ::operator new(sizeof(T)); // Now we have SPACE for a T object.
(T*)temp->T(); // Construct the contents of T.
object = (T *)temp; // assign `object`.
(对于学究的注意:上面的代码不是有效的 C++,也不是“你如何将一个 C++ 语句变成三个”——它的目的是描述一行中发生的事情,以某人的形式合理,但不是 C++ 专业知识可以理解的)。
它按此顺序发生,除非您的构造函数启动一个线程来执行一些“完成构造”的工作,否则您不能拥有object
未完全构造的值。
必须首先分配内存,然后初始化,最后调用类的构造函数。
我不知道中间步骤。对于您的表单operator new
,然后调用前者返回的内存上的构造函数。
此外,对象的虚拟表在构建完成之前不一定可用。
它是可用的——在某种意义上(该标准根本不要求 VMT,只是行为),简单来说,在构造过程中,类的行为就好像它是活动 ctor 的“最衍生”。可以发出虚拟调用,但它们从 Base::Base() 降落在 Base::foo 上,如果从 init 列表调用,则必须注意某些部分尚未构造。
我的问题是:operator new 能否在对象完成构造之前返回指向已分配/初始化内存的指针?
operator new
总是在 ctor 启动之前运行并完成。
但是您可能是指new operator
问题中的 as 。只有当一切都完成时才会返回,ctor 完成了它的工作。