安置新的基本实现是什么?

What is the underlying implementation of placement new?

提问人:akanesora 提问时间:7/6/2023 最后编辑:Jan Schultkeakanesora 更新时间:7/6/2023 访问量:122

问:

T *p = ::operator new(sizeof(T));
new (p) T;

我想知道该语法是如何工作的,因为放置 new 被声明为:

void* operator new(std::size_t, void*)

第二个参数似乎指向对象的存储,那么 C++ 如何连接到 ?void*new (p) Tvoid*

在 gcc libsupc++ 中,实现很简单:

// Default placement versions of operator new.
_GLIBCXX_NODISCARD inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
{ return __p; }

_GLIBCXX_NODISCARD inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
{ return __p; }

编译器是否负责将语法转换为放置的调用?new(*T) Toperator new

C++ GCC 放置 - 新

评论

0赞 NathanOliver 7/6/2023
Placement New 本身并没有真正做任何事情。它的作用是告诉编译器在提供指向的位置构造一个。这是必需的,因为作为程序员,您无法调用对象构造函数。TT*
2赞 Some programmer dude 7/6/2023
这只是正常的运算符过载。嗯,几乎正常。 将调用 .然后,您可以添加所需的任何类型的参数。例如,您可以创建一个可以像 .您甚至可以有多个参数。new Toperator new(size_t)operator new(size_t, int)new (123) T
0赞 Mooing Duck 7/6/2023
stackoverflow.com/questions/8918791/...
0赞 HolyBlackCat 7/6/2023
请注意,语法更通用。你可以把任何内容放在 之后,它就会被传递给 。(...)newoperator new(size,...)

答:

5赞 ComicSansMS 7/6/2023 #1

编译器是否负责将语法 new(*T) T 转换为 放置操作员的召唤 新?

是的,没错。

放置不能作为库函数实现,无论如何都需要编译器进行特殊处理。您在 libsupc++ 源代码中看到的实际实现在这里可能会产生误导,因为该实现不会反映放置新调用的大多数关键属性。new

评论

0赞 Mooing Duck 7/6/2023
placement new 不需要编译器进行任何特殊处理。它的工作方式与任何其他新表达式完全相同。人们只是感到困惑,因为我们几乎从不将参数传递给new
0赞 ComicSansMS 7/6/2023
@MooingDuck我的意思是,一般情况下,它不能作为库函数实现。我并不是要暗示放置是这里各种变体中的特例。operator newnewnew
0赞 Mooing Duck 7/6/2023
迂腐地讲,在一般:P中几乎总是作为库函数实现。但是你是对的,表达式不能,因为它也调用了构造函数。operator newnew
1赞 Mooing Duck 7/6/2023 #2

使用正则表达式可以做两件事:它调用分配内存的函数(但不构造),然后在该位置调用构造函数,以在该内存处创建对象。newoperator new

对于放置 new,是空操作,只返回传入的指针,然后编译器调用该位置的构造函数,以在该内存中创建对象。operator new(std::size_t, void*)

//normal version                   calls these two functions
MyClass* pMemory = new MyClass;    void* pMemory = operator new(sizeof(MyClass));
                                   MyClass::MyClass(pMemory); //pseudo-syntax

您还可以创建自己的自定义方法,这些方法也适用于相同的常规机制。new

void* operator new(std::size_t, const char* name) {
    return get_memory_by_name(name);
}

const char* allocation_name = "complex_float";
std::complex<float>* c = new(allocation_name) std::complex<float>{};