默认构造函数阻止调用emplace_back

Default constructor prevents from calling emplace_back

本文关键字:emplace back 调用 构造函数 默认      更新时间:2023-10-16
似乎

添加默认构造函数会阻止调用emplace_back并产生错误消息:"静态断言失败:类型不可分配"(gcc 5.3 和 -std=c++14)。下面是说明该问题的简单代码:

class A {
public:
    int a;
    A() = default;
    A(int a) {
        this->a = a;
    }
    A(A const & a) = delete;
    A& operator =(A const & a) = delete;
    A(A && a) = default;
    A& operator =(A && a) = default;
};
int main() {
    A a(4);
    std::vector<A> vec;
    vec.emplace_back(std::move(a)); // Error: type is not assignable
    return 0;
}

删除默认构造函数时,错误消失了!此外,如果定义了默认构造函数(即使它不执行任何操作),则错误也会消失:

class A {
public:
    int a;
    A() {
    }
    A(int a) {
        this->a = a;
    }
    A(A const & a) = delete;
    A& operator =(A const & a) = delete;
    A(A && a) = default;
    A& operator =(A && a) = default;
};
int main() {
    A b;
    A a(4);
    std::vector<A> vec;
    vec.emplace_back(std::move(a)); // Error gone
    return 0;
}

似乎"A() = default;"是导致问题的原因。这是编译器部分的正常行为还是错误?

这是一个

libstdc++错误(编辑:报告为错误69478)。

简而言之,libstdc++ 的std::vector,在这里相关,使用std::uninitialized_copy(与移动迭代器配对)在重新分配时移动元素,如果类型是微不足道的并且迭代器的引用类型是可分配的(即,概念上使用的赋值运算符是可用的),则将其减少到std::copy)。

然后,指向平凡类型的指针(或者在我们的例子中,包装指针的move_iterator)的std::copy反过来又优化为对memmove的调用以及对is_copy_assignable的检查。当然,在这种情况下,这种检查是错误的,因为uninitialized_copy与移动迭代器配对,只需要事物是可移动的。

如果没有默认构造函数,

或者默认构造函数是用户定义的,则类不是简单的,因此不会命中触发此 bug 的代码路径。