【发布时间】:2021-06-17 10:15:35
【问题描述】:
多年后我又回到了 C++,而且我使用的是 C++17 标准。根据this question,似乎具有 const 成员的自定义结构并不总是与没有公共复制分配构造函数的向量兼容。
在我的情况下,与链接的问题不同,以下编译得很好:
#include <vector>
struct Foo { const int m_Bar; };
int main()
{
std::vector<Foo> vecFoos{ Foo{1} };
vecFoos.push_back({ Foo{2} });
return 0;
}
以下不是:
#include <vector>
struct Foo { const int m_Bar; };
int main()
{
std::vector<Foo> vecFoos{ Foo{1} };
vecFoos.assign({ Foo{2} }); // using assign instead of push_back
return 0;
}
它失败了:
$ g++ --std=c++17 main.cpp && ./a.out
In file included from /usr/include/c++/9/vector:60,
from main.cpp:1:
/usr/include/c++/9/bits/stl_algobase.h: In instantiation of ‘static _Tp* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(const _Tp*, const _Tp*, _Tp*) [with _Tp = Foo; bool _IsMove = false]’:
/usr/include/c++/9/bits/stl_algobase.h:404:30: required from ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = const Foo*; _OI = Foo*]’
/usr/include/c++/9/bits/stl_algobase.h:441:30: required from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = const Foo*; _OI = Foo*]’
/usr/include/c++/9/bits/stl_algobase.h:474:7: required from ‘_OI std::copy(_II, _II, _OI) [with _II = const Foo*; _OI = Foo*]’
/usr/include/c++/9/bits/vector.tcc:321:29: required from ‘void std::vector<_Tp, _Alloc>::_M_assign_aux(_ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const Foo*; _Tp = Foo; _Alloc = std::allocator<Foo>]’
/usr/include/c++/9/bits/stl_vector.h:793:2: required from ‘void std::vector<_Tp, _Alloc>::assign(std::initializer_list<_Tp>) [with _Tp = Foo; _Alloc = std::allocator<Foo>]’
main.cpp:8:30: required from here
/usr/include/c++/9/bits/stl_algobase.h:382:39: error: static assertion failed: type is not assignable
382 | static_assert( __assignable::type::value, "type is not assignable" );
在一个不太简单的实际示例中,我尝试将一些具有 const 成员的结构重新分配给向量,但我遇到了这个问题,尽管编译器会抱怨不同的消息:
error: cannot bind rvalue reference of type ‘std::optional<long unsigned int>&&’ to lvalue of type ‘const std::optional<long unsigned int>’
在同一个输出中有不少:
error: non-static const member ‘const uint64_t myStruct::m_MyMember’, can’t use default assignment operator
error: no matching function for call to ‘std::optional<long unsigned int>::operator=(const std::optional<long unsigned int>&) const’
这三个有关系吗?我只是想了解为什么我可以将新元素重新分配给现有向量,以及这是否仅仅是因为我的结构没有显式的复制分配运算符。我怀疑答案是肯定的,因为添加我自己的复制分配构造函数确实绕过了示例代码中的问题:
Foo& operator=(Foo other) { return *this; }
但这似乎很愚蠢,我只是想找到一种明智的方法将这些重新分配给向量。
【问题讨论】:
-
你可以用
std::unique_ptr包裹你的元素。不过这会改变语法。 -
它不仅与向量有关,
foo1 = foo2分配也不起作用,vector::assign正在尝试有效并重新分配给现有对象。如果你不太关心这样的效率,你可以简单地用vecFoos = std::vector<Foo>({ Foo{2} });重新分配向量