[英]Questions about operator new() and operator delete()
Consider the following code and the questions below: 请考虑以下代码和以下问题:
/*
* GCC 4.4
*/
#include <iostream>
using namespace std;
class A {
public:
void* operator new(size_t s) {
cout << "A::operator new(size_t) called\n";
}
void operator delete(void* p) {
cout << "A::operator delete(void*) called\n";
}
void* operator new(size_t s, A* p) {
cout << "A::operator new(size_t, A*) called\n";
}
void operator delete(void* p, size_t s) {
cout << "A::operator delete(void*, size_t) called\n";
}
};
void* operator new(size_t s) {
cout << "::operator new(size_t) called\n";
}
void operator delete(void* p) {
cout << "::operator delete(void*) called\n";
}
void* operator new(size_t s, A* p) {
cout << "::operator new(size_t, A*) called\n";
}
void operator delete(void* p, size_t s) {
cout << "::operator delete(void*, size_t) called\n";
}
int main() {
A* p1 = new A(); // See question 1.
delete p1; // See question 2.
A* p2 = new (p1) A(); // See question 3.
delete p2; // See question 4.
}
The questions below might seem redundant somehow. 以下问题似乎有点多余。 However, what I am trying to distinguish is what is defined by the C++ standard rules from what is defined by the implementation.
但是,我想要区分的是C ++标准规则从实现定义的内容中定义的内容。
operator new(size_t)
will be used in any case (taken from A or from the global namespace, be it default or not). operator new(size_t)
将在任何情况下使用(取自A或来自全局命名空间,无论是否默认)。 This is OK. 还行吧。 Now try to remove
void* A::operator new(size_t) {}
only: why does the compiler gives: 现在尝试仅删除
void* A::operator new(size_t) {}
:为什么编译器会给出:
error: no matching function for call to 'A::operator new(unsigned int)' note: candidates are: static void* A::operator new(size_t, A*)
错误:没有匹配函数来调用'A :: operator new(unsigned int)'注意:候选者是:static void * A :: operator new(size_t,A *)
Connot the compiler pick up ::operator new(size_t)
from the global namespace? Connot编译器从全局命名空间中获取
::operator new(size_t)
?
Why is operator delete(void*)
preferred to operator delete(void*, size_t)
(when both of those versions are present in the same namespace where operator delete (void*)
is taken from)? 为什么
operator delete(void*)
首选于operator delete(void*, size_t)
(当这两个版本都出现在同一名称空间中,其中operator delete (void*)
取自)?
Why will not the code compile if I remove void* A::operator new(size_t, A*)
, although there is the same version of the operator defined in the global namespace? 如果我删除
void* A::operator new(size_t, A*)
,为什么代码不能编译,尽管在全局命名空间中定义了相同版本的运算符?
error: no matching function for call to 'A::operator new(unsigned int, A*&)' note: candidates are: static void* A::operator new(size_t)
错误:没有匹配函数来调用'A :: operator new(unsigned int,A *&)'注意:候选者是:static void * A :: operator new(size_t)
Why does the compiler still prefer operator delete (void*)
, although A::operator new(size_t, A*)
has been used for getting p2? 为什么编译器仍然喜欢
operator delete (void*)
,尽管A::operator new(size_t, A*)
已用于获取p2?
As to your first and third question, it IMO works like that: 关于你的第一个和第三个问题,IMO就是这样的:
If you explicitly state ::new
, it shouldn't have any problem. 如果你明确陈述
::new
,它应该没有任何问题。 The compiler only goes to the global namespace if it cannot find the specialized version of the new operator in the class. 如果编译器无法在类中找到新运算符的专用版本,则它只会转到全局命名空间。
From the standard: § 5.3.4, 从标准:§5.3.4,
9. If the new-expression begins with a unary :: operator, the allocation function's name is looked up in the global scope.
9.如果new-expression以一元::运算符开头,则在全局范围中查找分配函数的名称。 Otherwise, if the allocated type is a class type T or array thereof, the allocation function's name is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a class type, the allocation function's name is looked up in the global scope.
否则,如果分配的类型是类类型T或其数组,则在T的范围内查找分配函数的名称。如果此查找未能找到名称,或者如果分配的类型不是类类型,则分配函数的名称在全局范围内查找。
Let's imagine some scenarios. 让我们想象一些场景。 First off, the following always works:
首先,以下内容始终有效:
A * p1 = ::new A;
::delete p1;
A * p2 = ::new (addr) A; // assume "void * addr" is valid
p2->~A();
The global expressions always use the corresponding operators from the global namespace, so we're fine. 全局表达式总是使用全局命名空间中的相应运算符,所以我们没问题。 Note that there is no "placement-delete" expression .
请注意, 没有“placement-delete”表达式 。 Every placement-constructed object must be destroyed explicitly by calling the destructor.
必须通过调用析构函数显式地销毁每个placement-construct对象。
Next up, suppose we write: 接下来,假设我们写道:
A * p3 = new A;
delete p3;
This time round, the allocation function operator new(size_t)
is looked up in the A
's scope first. 这一次,首先在
A
的范围中查找分配函数operator new(size_t)
。 The name exists, but if you remove the correct overload, you have an error. 该名称存在,但如果删除正确的重载,则会出错。 (This answers Q1 and Q3.) The same goes for
operator delete()
. (这回答了Q1和Q3。)同样适用于
operator delete()
。 There's no particular reason why the one-parameter version ( (void *)
) is preferred over the two-argument version ( (void *, size_t)
); 单参数版本(
(void *)
)优于双参数版本( (void *, size_t)
)没有特别的原因; you should just have one of the two. 你应该只有两个中的一个。 (Note also that there's no global version of the two-argument function.)
(另请注意,双参数函数没有全局版本。)
Finally, let us revisit placement-new expressions. 最后,让我们重温一下展示新表达式。 Since there is no placement-delete expression , your final line of code is an error (undefined behaviour): You mustn't
delete
anything that wasn't obtained through a default- new
expression. 由于没有放置 - 删除表达式 ,因此最后一行代码是错误(未定义的行为):您不能
delete
任何未通过默认new
表达式获取的内容。 If you define a placement-new allocation function, you should also define the matching deallocation function. 如果定义了placement-new分配函数,则还应定义匹配的释放函数。 This function will only be called automatically on one specific situation, though: If a placement-new expression
new (a, b, c) Foo;
这个函数只会在一个特定情况下自动调用,但是:如果一个placement-new表达式
new (a, b, c) Foo;
causes the constructor to throw an exception, then the corresponding deallocation function is called. 导致构造函数抛出异常, 然后调用相应的释放函数。 Otherwise, since all placement-construction is manual, you will typically only call the placement deallocation function manually (and often never at all, because it rarely does any actual work).
否则,由于所有放置构造都是手动的,因此通常只会手动调用放置释放功能(通常根本不会,因为它很少做任何实际工作)。
The typical scenario might be something like this: 典型情况可能是这样的:
void * addr = ::operator new(sizeof(Foo)); // do real work
Foo * p = new (addr, true, 'a') Foo; // calls Foo::operator new(void*, bool, char);,
// then calls the constructor Foo::Foo()
// in case of exception, call Foo::operator delete(addr, true, 'a')
p->~Foo();
Foo::operator delete(addr, true, 'a'); // rarely seen in practice, often no purpose
::operator delete(addr); // do real work
To come full circle to the opening code example, note that the standard demands that the global ::operator delete(void *, void *)
do nothing. 要完整地讨论开头代码示例,请注意标准要求global
::operator delete(void *, void *)
不执行任何操作。 That is, global placement-new is required to need zero clean-up. 也就是说,全球布局新需要零清理。
An object does not remember how it was created; 对象不记得它是如何创建的; placement delete is only used when the corresponding placement new throws, otherwise the regular delete operator is used.
placement delete仅在相应的placement new throws时使用,否则使用常规delete操作符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.