Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我相信这是一个与放置新表达式相关的bug,它的构造函数抛出_C++_Clang_New Operator_C++14 - Fatal编程技术网

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::lib
operator 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&)