默认构造函数阻止调用 emplace_back
Posted
技术标签:
【中文标题】默认构造函数阻止调用 emplace_back【英文标题】:Default constructor prevents from calling emplace_back 【发布时间】:2016-01-25 21:08:28 【问题描述】:似乎添加默认构造函数会阻止调用emplace_back
并产生错误消息:“静态断言失败:类型不可分配”(gcc 5.3 with -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;"是导致问题的原因。 这是编译器部分的正常行为还是错误?
【问题讨论】:
clang 显示与 gcc 相同的行为 代码在c++11下使用gcc 4.7.2编译良好span> 影响课堂的琐碎性。 如果您使用 libc++,@jaggedSpire clang 会编译代码。这看起来像是 libstdc++ 的一个错误,它可能将针对琐碎类型的emplace_back
优化为 memcpy
调用,并且该调用链涉及调用一个断言该类型是可复制分配的函数。
@rustyx, A() = default;
可能是微不足道的,但A()
绝对不是。这可能会影响优化(在这种情况下,尽管 std::lib 的优化尝试存在错误)。
【参考方案1】:
这是一个 libstdc++ 错误(编辑:报告为 bug 69478)。
简而言之,libstdc++ 的std::vector
,与此处相关,使用std::uninitialized_copy
(与移动迭代器配对)在重新分配时移动元素,如果类型是微不足道的并且迭代器的引用类型是可分配的,则它减少为std::copy
(即,概念上使用的赋值运算符是可用的)。
然后,指向普通类型的指针的std::copy
(或者在我们的例子中,一个包装指针的move_iterator
)反过来被优化为对memmove
的调用以及对is_copy_assignable
的检查。当然,在这种情况下检查是错误的,因为 uninitialized_copy
与移动迭代器配对,只要求事物是可移动构造的。
如果您没有默认构造函数或者默认构造函数是用户定义的,那么该类就不是微不足道的,因此您不会点击触发此错误的代码路径。
【讨论】:
感谢您的回答。以上是关于默认构造函数阻止调用 emplace_back的主要内容,如果未能解决你的问题,请参考以下文章
学习 emplace_back() 和 push_back 的区别 emplace_back效率高
emplace_back() 和 push_back 的区别
[CPP]push_back和emplace_back的区别