繁体   English   中英

使用 clang 编译 libstdc++ 时出现问题

[英]Issue when compiling libstdc++ with clang

在使用 clang 编译 libstdc++(即 GNU 对 C++ 标准库的实现)时,我注意到了一个问题。 问题是,如果问题得到确认,我应该向谁报告?

当移动分配一个std::vector<X, A<X>>时会发生这种情况,条件是:

  1. X的移动构造函数可能会抛出(尽管我正在分配而不是构造);

  2. A<X>不会在移动赋值上传播,并且源向量和目标向量使用的分配器不比较相等。

一个MCVE紧随其后(现场观看)。 不幸的是,它包含一些样板,最重要的部分由注释指示。

#include <vector>
#include <memory>
#include <type_traits>

struct X {
    X() = default;
    X(const X&) = default;

    // Move constructor might throw
    X(X&&) noexcept(false) = default;

    // Track calls to assignment functions
    X& operator=(const X&) {
        putchar('c'); return *this;
    }
    X& operator=(X&&) noexcept(true) {
        putchar('m'); return *this;
    }
};

unsigned counter = 0;

template <typename T>
struct A : std::allocator<T> {

    template <typename U>
    struct rebind { using other = A<U>; };

    A() : std::allocator<T>(), id(++counter) {}

    // Does not propagate
    using propagate_on_container_move_assignment = std::false_type;

    // Does not always compare equal
    using is_always_equal = std::false_type;
    bool operator ==(const A& o) { return id == o.id; }
    bool operator !=(const A& o) { return id != o.id; }

    unsigned id;
};

int main() {
    std::vector<X, A<X>> a(2), rv(2);
    a = std::move(rv);
}

据我所知,clang++ 默认使用 libstdc++,使用 libc++ 是通过-stdlib=libc++选择加入的。 运行上面的代码(同样,使用 clang 和 libstdc++ 构建)显示cc ,这意味着rv的两个元素被复制分配a .

但是,引用[container.requirements.general]/4,表 83

“a 的所有现有元素要么被分配到移动,要么被销毁”

[container.requirements.general]/16, Table 86进一步证实了这一点。)

另一方面,通过将编译器切换到 gcc 或库切换到 libc++,我们得到与上面的引用一致的mm 通过将X(X&&)的异常规范更改为noexcept(true)也会发生这种情况,而operator =(X&&)的异常规范似乎无关紧要。

我错过了什么吗? 如果不是,我应该向谁报告问题? 它是 libstdc++ 或 clang。 (我认为这可能并不明显。)我倾向于认为是后者,因为 AFAIK,clang 应该支持 libstdc++ 而不是相反。

旁注:上面的代码至少可以揭示另一个问题,即从A中删除rebind使得 clang/libstdc++ 无法编译,而 clang/libc++ 成功。在我看来,在这种情况下,责任被逆转并落在 libstdc++ 上,但是这不是我的问题的一部分。)

libstdc++ 正在为此使用move_if_noexcept ,它可能不应该这样做。 错误报告应该 go 给他们。

rest 似乎是由于在如何处理具有异常规范不匹配的默认成员 function 方面存在分歧。 这是格式错误的,然后被删除,然后有效。 有关历史,请参阅P1286R2

  • Clang 认为“格式错误”然后“有效”,因此对于它编译的版本, move_if_noexcept将尝试复制。
  • GCC 认为“格式错误”然后“删除”。 但是被定义为默认的已删除移动构造函数被重载决议忽略,因此移动构造回退到使用默认的复制构造函数,它隐式地是 noexcept。 结果, move_if_noexcept会认为该类型是 nothrow move 可构造的并尝试移动。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM