gpt4 book ai didi

c++ - 我相信这是 clang 中的一个错误,与构造函数抛出的放置新表达式有关

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:33:59 25 4
gpt4 key购买 nike

new-expression 的形式为 new(std::nothrow) C; 时,问题就出现了其中 C是其构造函数抛出的类名。请参阅下面的代码和 live example使用 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';
}
}

g++打印以下内容,它似乎是正确的:

operator new(std::nothrow)
C()
operator delete(std::nothrow)
0x13f9c20
exception thrown in C(int) was caught
0

然而,如果您使用 clang ,您将获得以下输出:

operator new(std::nothrow)
C()
exception thrown in C(int) was caught
0x7fffecdeed00

也就是说,它看起来像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

编辑

回应@T.C. 的评论。下面以及其他那些说上面的代码具有未定义行为的人,我在下面展示了另一个代码,它显示了编译器应该如何操作,以正确编译上面的代码片段,使用 @T.C. 提供的伪代码。 here .另见 live example .需要注意的重要一点是,这段代码不使用 new-expression 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';
}
}

g++为此代码打印以下内容:

operator new(std::nothrow)
C()
operator delete(std::nothrow)
0x10c3c20
exception thrown in C() was caught
0x10c3c20

令人惊讶的是,clang似乎使用此代码可以正确执行操作,但不使用新表达式 new(nothrow) ,这清楚地表明 clang编译此新表达式时出现错误。

最佳答案

在我的系统 OS X 10.11.1 上,std::lib 提供的 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&)

你能在你的系统上做类似的分析并报告结果吗?

更新

感谢 T.C. 下面关于如何复制症状的说明,现在在我看来这是一个 clang 编译器代码生成错误,在 3.7 中引入,仍然存在于 tip-of-trunk 中,并且只能在 - O2(不是 -O1 或更低但不是 -O3)。

我认为错误报告是有序的,它应该有关于如何重现错误的很好的说明(除非你希望他们给予这个低优先级)。

附言

并设置 C *c = nullptr; 这样他们就不会浪费时间追逐不相关的 UB。

第二次更新

我仍然无法使用 clang tip-of-trunk 在本地重现此内容。但我可以在以下网站上看到它:

http://melpon.org/wandbox/permlink/5zIRyPJpq32LfU0t

我还没有对这种差异的解释。也许我的树干尖比他们的新?也许他们没有使用 libc++abi?

关于c++ - 我相信这是 clang 中的一个错误,与构造函数抛出的放置新表达式有关,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34120659/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com