【发布时间】:2018-03-28 06:17:42
【问题描述】:
我不确定我是否正确理解了 C++ 中的“大小释放”。 在 C++14 中,以下签名 was added 指向全局范围:
void operator delete(void* ptr, std::size_t size) noexcept
我正在使用 GCC 7.1.0 编译以下源代码:
#include <cstdio> // printf()
#include <cstdlib> // exit(),malloc(),free()
#include <new> // new(),delete()
void* operator new(std::size_t size)
{
std::printf("-> operator ::new(std::size_t %zu)\n", size);
return malloc(size);
}
void operator delete(void* ptr) noexcept
{
std::printf("-> operator ::delete(void* %p)\n", ptr);
free(ptr);
}
void operator delete(void* ptr, std::size_t size) noexcept
{
std::printf("-> operator ::delete(void* %p, size_t %zu)\n", ptr, size);
free(ptr);
}
struct B
{
double d1;
void* operator new(std::size_t size)
{
std::printf("-> operator B::new(std::size_t %zu)\n", size);
return malloc(size);
};
void operator delete(void* ptr, std::size_t size)
{
std::printf("-> operator B::delete(void* %p, size_t %zu)\n", ptr, size);
free(ptr);
};
virtual ~B()
{
std::printf("-> B::~B()");
}
};
struct D : public B
{
double d2;
virtual ~D()
{
std::printf("-> D::~D()");
}
};
int main()
{
B *b21 = new B();
delete b21;
B *b22 = new D();
delete b22;
D *d21 = new D();
delete d21;
std::printf("*****************************\n");
B *b11 = ::new B();
::delete b11;
B *b12 = ::new D();
::delete b12;
D *d11 = ::new D();
::delete d11;
return 0;
}
我得到以下输出:
-> operator B::new(std::size_t 16)
-> B::~B()-> operator B::delete(void* 0x16e3010, size_t 16)
-> operator B::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator B::delete(void* 0x16e3010, size_t 24)
-> operator B::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator B::delete(void* 0x16e3010, size_t 24)
*****************************
-> operator ::new(std::size_t 16)
-> B::~B()-> operator ::delete(void* 0x16e3010, size_t 16)
-> operator ::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator ::delete(void* 0x16e3010, size_t 16)
-> operator ::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator ::delete(void* 0x16e3010, size_t 24)
MS Visual Studio 2017 为我提供以下输出:
-> operator B::new(std::size_t 16)
-> B::~B()-> operator B::delete(void* 0081CDE0, size_t 16)
-> operator B::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator B::delete(void* 00808868, size_t 24)
-> operator B::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator B::delete(void* 00808868, size_t 24)
*****************************
-> operator ::new(std::size_t 16)
-> B::~B()-> operator ::delete(void* 0081CDE0, size_t 16)
-> operator ::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator ::delete(void* 00808868, size_t 24)
-> operator ::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator ::delete(void* 00808868, size_t 24)
而 Clang 5.0 甚至不调用全局大小的释放 operator delete(只是带有一个参数的 operator delete)。作为 T.C.评论部分提到的 Clang 需要附加参数 -fsized-deallocation 来使用大小分配,结果将与 GCC 相同:
-> operator B::new(std::size_t 16)
-> B::~B()-> operator B::delete(void* 0x219b6c0, size_t 16)
-> operator B::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator B::delete(void* 0x219b6c0, size_t 24)
-> operator B::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator B::delete(void* 0x219b6c0, size_t 24)
*****************************
-> operator ::new(std::size_t 16)
-> B::~B()-> operator ::delete(void* 0x219b6c0, size_t 16)
-> operator ::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator ::delete(void* 0x219b6c0, size_t 16)
-> operator ::new(std::size_t 24)
-> D::~D()-> B::~B()-> operator ::delete(void* 0x219b6c0, size_t 24)
对我而言,VS2017 似乎具有正确的行为,因为我对特定于类的运算符的理解是使用派生类的大小,即使在基类指针上调用 delete 也是如此。
我希望通过调用全局 operator delete 来实现对称行为。
我已经查看了 ISO C++11/14 标准,但我认为我没有找到任何关于全局和类本地运算符应该如何表现的具体内容(这可能只是我在解释标准的措辞,因为我不是母语人士)。
有人可以详细说明这个话题吗?
正确的行为应该是什么?
【问题讨论】:
-
请注意,编译器不需要使用用户提供的
new和delete(和/或根本不使用new和delete),如果它可以证明它没有'不要改变程序的语义。 -
Clang 需要
-fsized-deallocation,然后它与 GCC 一致。但是,看起来 MSVC 在这里得到了它。
标签: c++ memory c++14 delete-operator