在堆上构造对象在C ++语言中看起来很简单。当代码
T* object = new T();
func(object);
调用,我的理解是必须首先分配内存,然后初始化,最后调用类的构造函数。此外,在构造完成后
之前,对象的虚拟表不一定可用。我的问题是:operator new
可以在对象构建完成之前返回指向已分配/初始化内存的指针,以便func(...)
对未完全构造的对象进行操作吗?这个问题的答案对我正在开发的多线程库有影响。
提前致谢。
答案 0 :(得分:6)
operator new
分配内存。 new
关键字(在示例代码中使用)使用operator new
来分配内存,然后构造该内存中的对象。并且,是的,在没有正确同步的多线程应用程序中,指针值可以在构造函数的副作用发生之前在其他线程中可见。这是因为每个处理器都可以有一个单独的缓存,并且在构造函数的副作用被读入缓存之前,指针值可能会被读入缓存。阅读“双重检查锁定”了解更多详情。
答案 1 :(得分:1)
object
在构造之前不会指向对象。 new T()
在完成之前不会返回。
我猜Pete Becker的缓存问题是正确的......
答案 2 :(得分:1)
我认为产生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
中创建一个未完全构造的值。
答案 3 :(得分:0)
必须首先分配内存,然后初始化,最后调用类的构造函数。
我不知道中间步骤。对于您的表单,operator new
被调用,然后是前者返回的内存上的构造函数。
此外,在构建完成之前,对象的虚拟表不一定可用。
它是可用的 - 在某种意义上(标准根本不要求VMT,只是行为),简单来说,在构造过程中,类的行为就好像它是活动ctor的“最多派生”。可以发出虚拟调用但它们从Base :: Base()调用Base :: foo,如果从init列表调用,则必须注意某些部分尚未构建。
我的问题是:运算符new可以在对象构造完成之前返回指向已分配/初始化内存的指针吗?
operator new
始终在ctor启动之前运行并完成。
但你的意思可能是new operator
。只有当一切都完成后,ctor才能完成它的工作。