c++ - 为什么我的数据元素被复制而不是移动?
问题描述
我正在执行一些关于移动语义的测试,我的课堂行为对我来说似乎很奇怪。
鉴于模拟类VecOfInt
:
class VecOfInt {
public:
VecOfInt(size_t num) : m_size(num), m_data(new int[m_size]) {}
~VecOfInt() { delete[] m_data; }
VecOfInt(VecOfInt const& other) : m_size(other.m_size), m_data(new int[m_size]) {
std::cout << "copy..." <<std::endl;
std::copy(other.m_data, other.m_data + m_size, m_data);
}
VecOfInt(VecOfInt&& other) : m_size(other.m_size) {
std::cout << "move..." << std::endl;
m_data = other.m_data;
other.m_data = nullptr;
}
VecOfInt& operator=(VecOfInt const& other) {
std::cout << "copy assignment..." << std::endl;
m_size = other.m_size;
delete m_data;
m_data = nullptr;
m_data = new int[m_size];
m_data = other.m_data;
return *this;
}
VecOfInt& operator=(VecOfInt&& other) {
std::cout << "move assignment..." << std::endl;
m_size = other.m_size;
m_data = other.m_data;
other.m_data = nullptr;
return *this;
}
private:
size_t m_size;
int* m_data;
};
好的案例
当我就地插入单个值时:
int main() { std::vector<VecOfInt> v; v.push_back(10); return 0; }
然后它给了我以下输出(我认为很好):
move...
奇怪的情况
当我就地插入三个不同的值时:
int main() { std::vector<VecOfInt> v; v.push_back(10); v.push_back(20); v.push_back(30); return 0; }
然后输出调用复制构造函数 3 次:
move... move... copy... move... copy... copy...
我在这里缺少什么?
解决方案
重新分配时不使用移动构造和移动分配,std::vector
除非它们是noexcept
或没有复制替代方案。这是您noexcept
添加的示例:
class VecOfInt {
public:
VecOfInt(size_t num) : m_size(num), m_data(new int[m_size]) {}
~VecOfInt() { delete[] m_data; }
VecOfInt(VecOfInt const& other) : m_size(other.m_size), m_data(new int[m_size]) {
std::cout << "copy..." <<std::endl;
std::copy(other.m_data, other.m_data + m_size, m_data);
}
VecOfInt(VecOfInt&& other) noexcept : m_size(other.m_size) {
std::cout << "move..." << std::endl;
m_data = other.m_data;
other.m_data = nullptr;
}
VecOfInt& operator=(VecOfInt const& other) {
std::cout << "copy assignment..." << std::endl;
m_size = other.m_size;
delete m_data;
m_data = nullptr;
m_data = new int[m_size];
m_data = other.m_data;
return *this;
}
VecOfInt& operator=(VecOfInt&& other) noexcept {
std::cout << "move assignment..." << std::endl;
m_size = other.m_size;
m_data = other.m_data;
other.m_data = nullptr;
return *this;
}
private:
size_t m_size;
int* m_data;
};
一个活生生的例子输出:
move...
move...
move...
move...
move...
move...
这样做是为了保持异常安全。调整大小std::vector
失败时,它将尝试使向量保持尝试前的状态。但是,如果移动操作在重新分配中途抛出,则没有安全的方法可以撤消已经成功进行的移动。他们也很可能会扔。如果移动可能会抛出,最安全的解决方案是复制。
推荐阅读
- sql-server - 如何查询包含单引号的数据库字段?
- java - 为什么在这两种情况下 unicode 编码不同?
- javascript - 基于另一个参数约束参数类型的最有效方法
- bash - 删除文件中的行直到特定行
- javascript - 根据选项隐藏/显示 DIV 不起作用
- javascript - 使用中继器 asp.net 网络表单尝试动态轮播滑块
- ios - 如何在 UICollectionViewCell 中有一个自动换行标签,其右锚点约束到单元格的右锚点?
- groovy - 如何禁用groovyscript中的警告?
- github - Sonarqube 徽章在 github README 上不起作用
- python - 在python中匹配和添加reg表达式值