在不使用元素复制赋值运算符的情况下复制向量 - 可移植性
Copying vectors without using the element copy assignment operator - portability
如果我有这样的类型:
class Foo {
public:
Foo();
Foo(const Foo&);
Foo& operator=(const Foo&) = delete;
...
private:
...
};
我有两个这种类型的向量:
std::vector<Foo> x;
std::vector<Foo> y;
而且我想将x
的内容复制到y
,有没有跨平台的方法?
VC++将使用y.assign(x.begin(), x.end())
来做到这一点,它使用Foo
的复制构造函数而不是删除的复制赋值运算符。 但是GCC抱怨缺少复制分配运算符,无论您是尝试y = x
还是y.assign(x.begin(), x.end())
。
有没有办法在两者中都有效?
该标准要求要使y.assign(it1, it2)
正常工作,元素类型T
可复制的。也就是说,复制可构造和可分配。您的类型不可分配,因此您不能依赖 assign
。y = x
也是如此.该标准的第23.2.3节描述了各种序列容器操作的要求。
如果你有一个现有的向量y
,你可以构造一个新的向量z
然后用y
交换它:
{
std::vector<Foo> z(x.begin(), x.end());
z.swap(y);
}
这使用范围构造函数,它只需要T
EmplaceConstructible
,不需要赋值运算符!然后,您可以交换基础内存,而无需任何其他副本。
请注意,这可能会导致更大的内存使用量,因为 y
的任何现有内容都将保留,直到新交换的z
超出范围。您可以尝试通过首先执行以下操作来缓解此问题
y.clear();
y.shrink_to_fit();
尽管shrink_to_fit()
只是一个请求,并且您的库实现可能不会满足。
[现场演示]
在 C++11 之前,你的代码是不可能的:向量元素类型必须是CopyAssignable
的,这意味着可复制构造和可分配。 请注意,如果类型不满足这些要求,则代码格式不正确,无需诊断;这使编译器可以自由地接受或拒绝它。
自C++11以来,各个操作都有自己的要求。vector
的相关要求是(来源:C++14表100(:
-
emplace_back
:MoveInsertible
和MoveAssignable
-
insert
:CopyInsertable
和CopyAssignable
- 构造函数:
EmplaceConstructible
这些特征的含义是(大致(:
-
CopyInsertable
:具有复制构造函数 -
MoveInsertable
:具有复制构造函数或移动构造函数(或两者兼而有之( -
CopyAssignable
:具有复制构造函数和复制赋值运算符 -
MoveAssignable
:MoveInsertable
,并且具有复制赋值或移动赋值运算符(或两者兼而有之( -
EmplaceConstructible
: 具有构造函数
这里的基本原理是,任何插入都可能导致内存重新分配,这要求能够复制或移动对象。但是,该标准不要求编译器测试构造函数或赋值运算符是否各自可用,如果另一个不可用,则使用其中一个。相反,它指定两者都必须可用。
您没有指定您的类是否可移动。假设不是,那么这意味着您不能使用任何 emplace 或 insert 方法,也不能使用任何其他可能导致重新分配的函数。
如果你当时正在创建y
那么你当然可以使用初始化:
vector<int> y = x;
如果y
已经存在,正如您的问题所暗示的那样,那么您几乎不走运:您不能使用任何插入函数,因此您只能修改现有元素。由于没有赋值运算符,因此无法通过赋值执行此操作。
但是你可以按照安德鲁的回答中的建议使用y.swap()
。
构造函数和移动赋值添加到类中,或者重新设计代码,以便不需要分配给y
。(例如,使用指针(。
如果x.size() == y.size()
,则可以使用放置新作为最后的手段:
for (size_t i = 0; i != y.size(); ++i)
{
y[i].~Foo();
new(&y[i]) Foo(x[i]); // copy-construct
}
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 在不复制临时对象的情况下延长其生存期
- 在这种情况下,我真的复制了字节还是复制了字符?
- QT QOpenGLWidget:如何在不使用数据块复制的情况下修改VBO中的单个顶点值?
- 如何在不复制的情况下将一个向量移动到另一个向量中
- 如何在没有复制构造函数的情况下为地图设置值?
- 在这种情况下,使用 string_view 是否会导致不必要的字符串复制?
- 我有两棵二叉树.我想在不更改输入树的情况下深度复制两个二叉树的结果
- 如何在不复制的情况下操作 QByteArray 对象?
- 在不复制数据的情况下,将double数组转换为只有double成员的structs数组
- 有没有一种方法可以在不复制数据的情况下从string_view创建字符串流
- 是否可以在不复制的情况下访问undered_map中的元素
- 如何在不复制数据的情况下将 cv::Mat 转换为 2d 标准::矢量
- 如何在不复制列表的情况下将列表传递给线程,同时销毁原始列表
- 是否有可能在没有复制的情况下传递 std::vector<int> 作为参数来获得 std::vector<std::array<int, 3>>?
- 是否可以在不显式迭代每个元素的情况下深度复制指针容器?
- 如何在不复制此代码的情况下将多个函数放入多个命名空间?
- 父类有 26 个构造函数重载.如何在不复制+粘贴 26 个重载的情况下将一个小任务附加到所有构造器?
- 如何在自定义删除器的情况下复制unique_ptr
- 如何在不复制的情况下比较字符串的一部分?