C++ 我相信这是一个与放置新表达式相关的bug,它的构造函数抛出
当形式为C++ 我相信这是一个与放置新表达式相关的bug,它的构造函数抛出,c++,clang,new-operator,c++14,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::noth
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';
}
}
然而,如果使用clang
,您将获得以下输出:
operator new(std::nothrow)
C()
exception thrown in C(int) was caught
0x7fffecdeed00
也就是说,似乎clang
不是调用程序中定义的操作符delete(void*,std::nothrow\u t&)
,而是调用标准库中的操作符
奇怪的是,通过在我的系统OS X 10.11.1上删除表达式
std::cout,提供的std::liboperator delete
位于/usr/lib/libc++abi.dylib中。在类Unix系统上,此签名通过赋予它“弱链接”而可替换。当链接器看到两个相同的签名,并且其中一个链接较弱时,它会选择没有链接的签名
我可以确认,在我的系统上,运算符delete(void*,std::nothrow\u 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&)
你能对你的系统做类似的分析并报告结果吗
更新
多亏了T.C.下面关于如何复制症状的说明,我现在觉得这是一个在3.7中引入的编译器代码生成错误,仍然存在于主干的顶端,并且只能在-O2(不是-O1或更低,也不是-O3)下重现
我认为一个bug报告已经准备好了,它应该有关于如何重现bug的很好的说明(除非你想让他们给这个低优先级)
PS
并设置C*C=nullptr代码>这样他们就不会浪费时间追逐不相关的UB
第二次更新
我仍然不能用树干顶端的叮当声在本地复制这个。但我可以在以下网站上看到:
我还没有对这种差异的解释。也许我的躯干尖端比他们的更近?可能他们没有使用libc++abi?读取未初始化的值c
,这是一种未定义的行为。您的类构造函数会抛出,因此对c
的赋值永远不会发生。@Belloc:no。分配c
的命令永远不会完成。现在,new
的结果可以在调用构造函数之前放在c
使用的内存位置,也可以放在寄存器中。您唯一能保证的是,如果语句完成,c
的值设置为new
的结果。我能想到的唯一会导致这种行为的原因是编译的std::lib没有将操作符delete
标记为弱符号。这可能是std::lib中的一个bug,也可能是其构建过程中的bug;它甚至不在任何地方分配A*
。在您的代码中,c
在catch块中未初始化-Loki和Kerrek是正确的。我不熟悉clang和g++。我只是使用他们的网络编译器。因此,除非你确切地告诉我如何进行,否则我将无法在这里帮助你。但正如我上面所说的,如果我们在main()
中的catch子句中取消使用变量c
,UB的原因就会消失,而clang会继续调用默认的操作符delete(nothrow)
,而不是代码中给出的可替换版本。据我所知,这是一个bug。@Belloc您必须更具体地描述您的环境。跟踪出现在某些web编译器前端但并非无处不在的错误是没有用的。当你输入你的例子和正确的标志时,尝试一个工作的铿锵版本。读起来一点也不好笑,你是基于无法访问以进行进一步分析的安装而打开此问题的。@Belloc:演示如何复制不起作用的内容。我不认为这是链接器问题。检查表明根本没有发出对运算符delete(void*,const nothrow\u t&)的调用。@HowardHinnant向我们展示如何复制不起作用的内容。
请参阅。如果将-O2更改为-O1或-O3,代码将按预期工作。
operator new(std::nothrow)
C()
operator delete(std::nothrow)
exception thrown in C(int) was caught
0x7fffc0ffc000
#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';
}
}
operator new(std::nothrow)
C()
operator delete(std::nothrow)
0x10c3c20
exception thrown in C() was caught
0x10c3c20
$ 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&)