[英]"result type must be constructible from value type of input range" when creating a std::vector
[英]vector resize with move assignment: result type must be constructible from input type
我想尝试向下面的Mesh
class 添加一个移动赋值运算符,知道 Meshes 的向量作为字段成员出现在我的Model
class 中:
#include <vector>
struct Mesh {
std::vector<int> vertexes;
Mesh() {
}
Mesh& operator=(Mesh&& m) {
vertexes = std::move(m.vertexes);
return *this;
}
};
struct Model {
std::vector<Mesh> meshes;
Model() {
meshes.resize(10);
}
};
int main() {
Model model;
return 0;
}
但是这段代码不起作用。 下面是我得到的错误(clang 比 gcc 更明确):
In file included from script.cpp:1:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/vector:63:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:90:7: error: static_assert failed due to requirement 'is_constructib
le<Mesh, Mesh &&>::value' "result type must be constructible from input type"
static_assert(is_constructible<_ValueType, _Tp>::value,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:182:4: note: in instantiation of function template specialization 's
td::__check_constructible<Mesh, Mesh &&>' requested here
= _GLIBCXX_USE_ASSIGN_FOR_INIT(_ValueType2, _From);
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:101:13: note: expanded from macro '_GLIBCXX_USE_ASSIGN_FOR_INIT'
&& std::__check_constructible<T, U>()
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:372:19: note: in instantiation of function template specialization '
std::uninitialized_copy<std::move_iterator<Mesh *>, Mesh *>' requested here
return std::uninitialized_copy(__first, __last, __result);
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:396:19: note: in instantiation of function template specialization '
std::__uninitialized_copy_a<std::move_iterator<Mesh *>, Mesh *, Mesh>' requested here
return std::__uninitialized_copy_a
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/vector.tcc:674:14: note: in instantiation of function template specialization 'std::__un
initialized_move_if_noexcept_a<Mesh *, Mesh *, std::allocator<Mesh>>' requested here
std::__uninitialized_move_if_noexcept_a(
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_vector.h:1011:4: note: in instantiation of member function 'std::vector<Mesh>::_M_de
fault_append' requested here
_M_default_append(__new_size - size());
^
script.cpp:20:12: note: in instantiation of member function 'std::vector<Mesh>::resize' requested here
meshes.resize(10);
In file included from script.cpp:1:
In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/vector:62:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_construct.h:119:25: error: call to implicitly-deleted copy constructor of 'Mesh'
::new((void*)__p) _Tp(std::forward<_Args>(__args)...);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:120:11: note: in instantiation of function template specialization '
std::_Construct<Mesh, Mesh>' requested here
std::_Construct(std::__addressof(*__cur), *__first);
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:137:16: note: in instantiation of function template specialization '
std::__do_uninit_copy<std::move_iterator<Mesh *>, Mesh *>' requested here
{ return std::__do_uninit_copy(__first, __last, __result); }
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:185:2: note: in instantiation of function template specialization 's
td::__uninitialized_copy<false>::__uninit_copy<std::move_iterator<Mesh *>, Mesh *>' requested here
__uninit_copy(__first, __last, __result);
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:372:19: note: in instantiation of function template specialization '
std::uninitialized_copy<std::move_iterator<Mesh *>, Mesh *>' requested here
return std::uninitialized_copy(__first, __last, __result);
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_uninitialized.h:396:19: note: in instantiation of function template specialization '
std::__uninitialized_copy_a<std::move_iterator<Mesh *>, Mesh *, Mesh>' requested here
return std::__uninitialized_copy_a
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/vector.tcc:674:14: note: in instantiation of function template specialization 'std::__un
initialized_move_if_noexcept_a<Mesh *, Mesh *, std::allocator<Mesh>>' requested here
std::__uninitialized_move_if_noexcept_a(
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/12.2.0/../../../../include/c++/12.2.0/bits/stl_vector.h:1011:4: note: in instantiation of member function 'std::vector<Mesh>::_M_de
fault_append' requested here
_M_default_append(__new_size - size());
^
script.cpp:20:12: note: in instantiation of member function 'std::vector<Mesh>::resize' requested here
meshes.resize(10);
^
script.cpp:9:9: note: copy constructor is implicitly deleted because 'Mesh' has a user-declared move assignment operator
Mesh& operator=(Mesh&& m) {
^
我确实意识到:
我的问题是:
为什么std::vector::resize()
在定义空构造函数时尝试调用已删除的复制构造函数来为新项分配空间?
它是否因为未满足std::vector::resize()
的要求之一而失败?
如果是这样,我如何在不删除移动分配的情况下满足它? (如果我的代码有效,与 resize() 相同)。
std::vector::resize()
要求T
为MoveInsertible和DefaultInsertable 。
如果
A
是std::allocator<T>
,则这将调用 placement-new,如::new((void*)p) T(rv)
(C++20 前)std::construct_at(p, rv)
(C++20 起) 。 这实际上要求T
是移动可构造的。如果使用
std::allocator<T>
或类似的分配器,则class 不必实现移动构造函数来满足此类型要求:采用const T&
参数的复制构造函数可以绑定右值表达式。 如果MoveInsertable class 实现移动构造函数,它也可以实现移动语义以利用构造后rv
的值未指定的事实。
每个Move 构造函数:
隐式声明的移动构造函数
如果没有为 class 类型(
struct
、class
或union
)提供用户定义的移动构造函数,并且以下所有条件都为真:然后编译器会将移动构造函数声明为其 class 的非显式
inline public
成员,其签名为T::T(T&&)
。
您的Mesh
class 没有任何用户声明的复制/移动构造函数,但它确实有一个用户声明的移动赋值运算符。 因此, Mesh
没有编译器生成的 move 构造函数,因此它不是move constructible ,因此不满足MoveInsertible的要求,因此编译器错误。
要按照您的要求在不删除移动赋值运算符的情况下解决此问题,您需要将用户声明的复制构造函数和/或移动构造函数添加到Mesh
,例如:
struct Mesh {
std::vector<int> vertexes;
Mesh() {
}
Mesh(const Mesh& m) : vertexes(m.vertexes) {
}
// and/or:
Mesh(Mesh&& m) : vertexes(std::move(m.vertexes)) {
}
// in which case, you may as well consider adding this, too:
Mesh& operator=(const Mesh& m) {
if (this != &m) {
vertexes = m.vertexes;
}
return *this;
}
Mesh& operator=(Mesh&& m) {
vertexes = std::move(m.vertexes);
return *this;
}
};
但是, std::vector
本身是完全可复制和移动的,因此如果您可以忘记不必要的要求并完全摆脱移动赋值运算符,那么所有编译器生成的构造函数和赋值运算符都足以满足此示例:
struct Mesh {
std::vector<int> vertexes;
};
您的 class Mesh 声明了一个显式默认构造函数,默认情况下会删除移动构造函数。
要么不声明构造函数,要么声明所有这 5 个函数:
在大多数情况下(但不是全部),默认值应该可以正常工作。
例子:
#include <vector>
// Quick explanation of the rules of 0, 3 and 5
struct Mesh_rule_of_0 {
std::vector<int> vertices;
// rule of zero. No explicit constructors, nor operator=() defined.
// The compiler will generate implicit defaults for you.
};
struct Model_0 {
std::vector<Mesh_rule_of_0> meshes;
Model_0() { meshes.resize(10); }
};
struct Mesh_rule_of_3 {
std::vector<int> vertices;
// if one of these 3 is defined, then all three must be defined
// The compiler will _try_ to generate implicit move operations for you.
Mesh_rule_of_3() = default;
Mesh_rule_of_3(const Mesh_rule_of_3&) = default;
Mesh_rule_of_3& operator=(const Mesh_rule_of_3&) = default;
};
struct Model_3 {
std::vector<Mesh_rule_of_3> meshes;
Model_3() { meshes.resize(10); }
};
struct Mesh_rule_of_5 {
std::vector<int> vertices;
// rule of 5, if a move operator is defined, all 5 must be
// defined.
Mesh_rule_of_5() = default;
Mesh_rule_of_5(const Mesh_rule_of_5&) = default;
Mesh_rule_of_5(Mesh_rule_of_5&&) = default;
Mesh_rule_of_5& operator=(const Mesh_rule_of_5&) = default;
Mesh_rule_of_5& operator=(Mesh_rule_of_5&&) = default;
};
struct Model_5 {
std::vector<Mesh_rule_of_5> meshes;
Model_5() { meshes.resize(10); }
};
struct Mesh_fail {
std::vector<int> vertices;
// this will fail, because it doesn't satisfy the requirements
// of the rule of 0, nor of the rule of 3 nor of
// the rule of 5
Mesh_fail() {}
Mesh_fail& operator=(Mesh_fail&&) = default;
};
// uncomment for failure
// struct Model_fail {
// std::vector<Mesh_fail> meshes;
// Model_fail() { meshes.resize(10); }
// };
int main() {
Model_0 m0;
Model_3 m3;
Model_5 m5;
// uncomment for failure
// Model_fail mf;
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.