Bel*_*loc 6 c++ clang new-operator c++14
当一个问题出现了新的表达形式new(std::nothrow) C;哪里C是一个类名,其构造函数抛出.使用以下代码查看下面的代码和实例g++:
#include <iostream>
void* operator new(std::size_t size, const std::nothrow_t&) noexcept
{
void* p;
p = malloc(size);
std::cout << "operator new(std::nothrow)" << '\n';
return p;
}
void operator delete(void* p, const std::nothrow_t&) noexcept
{
free(p);
std::cout << "operator delete(std::nothrow)" << '\n';
std::cout << p << '\n';
}
class T{};
class C {
int i;
public:
C(int i) : i{i} { std::cout << "C()" << '\n'; throw T{}; }
~C() { std::cout << "~C()" << '\n'; }
};
int main()
{
C* c;
try { c = new(std::nothrow) C(3); }
catch (T&)
{
std::cout << "exception thrown in C(int) was caught" << '\n';
std::cout << c << '\n';
}
}
Run Code Online (Sandbox Code Playgroud)
g++ 打印以下内容似乎是正确的:
operator new(std::nothrow)
C()
operator delete(std::nothrow)
0x13f9c20
exception thrown in C(int) was caught
0
Run Code Online (Sandbox Code Playgroud)
然而,如果您使用clang,您将获得以下输出:
operator new(std::nothrow)
C()
exception thrown in C(int) was caught
0x7fffecdeed00
Run Code Online (Sandbox Code Playgroud)
也就是说,它好像clang是不调用operator delete(void*, std::nothrow_t&)在程序中定义,并呼吁相反,运营商在标准库.
奇怪的是,通过只删除表达式std::cout << p << '\n';的operator delete(void*, std::nothrow_t&),在代码中定义的,clangs似乎正确执行,打印:
operator new(std::nothrow)
C()
operator delete(std::nothrow)
exception thrown in C(int) was caught
0x7fffc0ffc000
Run Code Online (Sandbox Code Playgroud)
编辑
为了回应@TC下面的评论和其他人说上面的代码有未定义的行为,我在下面提供另一个代码,显示编译器应该如何操作,正确编译上面的代码片段,使用由以下代码提供的伪代码: @TC 在这里.另请参见此实例.要注意的重要一点是,这个代码不使用的新的表达 new(nothrow).
#include <iostream>
void * operator new(std::size_t n)
{
void* p;
try { p = malloc(n); }
catch (std::bad_alloc&) { throw; }
std::cout << "operator new" << '\n';
return p;
}
void operator delete(void *p) noexcept
{
free(p);
std::cout << "operator delete" << '\n';
}
void* operator new(std::size_t size, const std::nothrow_t&) noexcept
{
void* p = malloc(size);
std::cout << "operator new(std::nothrow)" << '\n';
return p;
}
void operator delete(void* p, const std::nothrow_t&) noexcept
{
free(p);
std::cout << "operator delete(std::nothrow)" << '\n';
std::cout << p << '\n';
}
class T {};
class C {
int i;
public:
C(int i) : i{ i } { std::cout << "C()" << '\n'; throw T{}; }
~C() { std::cout << "~C()" << '\n'; }
};
int main()
{
C *c;
try
{
c = (C*)operator new(sizeof(C), std::nothrow);
struct cleanup
{
void* p;
bool active;
~cleanup() { if (active) operator delete(p, std::nothrow); }
void dismiss() { active = false; }
} guard = { (void*)c, true };
new(c) C{1};
guard.dismiss();
}
catch ( std::bad_alloc& ) { c = nullptr; }
catch (T&)
{
std::cout << "exception thrown in C() was caught" << '\n';
std::cout << c << '\n';
}
}
Run Code Online (Sandbox Code Playgroud)
g++ 为此代码打印以下内容:
operator new(std::nothrow)
C()
operator delete(std::nothrow)
0x10c3c20
exception thrown in C() was caught
0x10c3c20
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,clang似乎使用此代码正确操作,该代码不使用new-expression new(nothrow),这清楚地表明clang在编译此new-expression时存在错误.
在我的系统OS X 10.11.1上,std :: lib-provided operator delete位于/usr/lib/libc++abi.dylib中.在类Unix系统上,这个签名通过赋予它"弱连接"而可以替换.当链接器看到两个相同的签名,并且其中一个具有弱连接时,它将更喜欢那个没有的签名.
我可以确认在我的系统上,operator delete(void*, std::nothrow_t const&)与以下命令的链接很弱:
$ nm -gm /usr/lib/libc++abi.dylib |c++filt |grep nothrow_t
0000000000024406 (__TEXT,__text) weak external operator delete[](void*, std::nothrow_t const&)
00000000000243fc (__TEXT,__text) weak external operator delete(void*, std::nothrow_t const&)
00000000000243c0 (__TEXT,__text) weak external operator new[](unsigned long, std::nothrow_t const&)
000000000002437e (__TEXT,__text) weak external operator new(unsigned long, std::nothrow_t const&)
Run Code Online (Sandbox Code Playgroud)
您能对系统进行类似的分析并报告结果吗?
更新
感谢TC下面关于如何复制症状的说明,它现在在我看来这是一个clang编译器代码生成错误,在3.7中引入,仍然存在于主干中,并且只能在-O2(不是-O1)重现或更低而不是-O3).
我认为错误报告是有序的,它应该有关于如何重现错误的良好指示(除非你希望它们给它一个低优先级).
PS
并设置,C *c = nullptr;以便他们不浪费时间追逐不相关的UB.
第二次更新
我仍然无法使用clang tip-of-trunk在本地重现这一点.但我可以在以下网站上看到它:
http://melpon.org/wandbox/permlink/5zIRyPJpq32LfU0t
我还没有解释这种差异.也许我的行李箱比他们的更近?也许他们没有使用libc ++ abi?
| 归档时间: |
|
| 查看次数: |
618 次 |
| 最近记录: |