c++ - copy-and-swap 总是最好的解决方案吗?

标签 c++

我看过copy-and-swap various中推荐的成语places作为为赋值运算符实现强异常安全性的推荐/最佳/唯一方法。在我看来,这种方法也有缺点。

考虑以下使用 copy-and-swap 的简化类 vector 类:

class IntVec {
  size_t size;
  int* vec;
public:
  IntVec()
    : size(0),
      vec(0)
  {}
  IntVec(IntVec const& other)
    : size(other.size),
      vec(size? new int[size] : 0)
  {
    std::copy(other.vec, other.vec + size, vec);
  }

  void swap(IntVec& other) {
    using std::swap;
    swap(size, other.size);
    swap(vec, other.vec);
  }

  IntVec& operator=(IntVec that) {
    swap(that);
    return *this;
  }

  //~IntVec() and other functions ...
}

通过复制构造函数实现分配可能是高效的并保证异常安全,但它也可能导致不必要的分配,甚至可能导致未调用的内存不足错误。

考虑在具有 <2GB 堆限制的机器上将 700MB IntVec 分配给 1GB IntVec 的情况。最佳分配将意识到它已经分配了足够的内存,并且只将数据复制到已经分配的缓冲区中。 copy-and-swap 实现将导致在释放 1GB 缓冲区之前分配另一个 700MB 缓冲区,导致所有 3 个缓冲区同时尝试在内存中共存,这将不必要地引发内存不足错误。

这个实现可以解决问题:

IntVec& operator=(IntVec const& that) {
  if(that.size <= size) {
    size = that.size;
    std::copy(that.vec, that.vec + that.size, vec);
  } else
    swap(IntVec(that));
  return *this;
}

所以底线是:
我是对的,这是 copy-and-swap 习语的问题,还是正常的编译器优化以某种方式消除了额外的分配,或者我忽略了 copy-and-swap 解决的“更好”版本的一些问题,还是我的数学/算法做错了,问题并不存在?

最佳答案

实现重用空间有两个问题

  • 如果您分配 very_huge_vect = very_small_vect; 额外的内存将不会被释放。这可能是您想要的,也可能不是。

  • 如果是整数,一切都很好,但是复制操作可能会抛出异常的对象呢?您最终会得到一个困惑的数组,其中部分拷贝已完成并且已被截断。如果复制操作失败(交换习语的作用),最好保持目标不变。

顺便说一句,作为一般规则,在极少数情况下,您可以找到看起来“始终是最佳解决方案”的任何东西。如果您正在寻找 Elixir ,那么编程将不是正确的地方。

关于c++ - copy-and-swap 总是最好的解决方案吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23918469/

相关文章:

c++ - 无法将 ‘void* (Network::*)(void*)’ 转换为 ‘void* (*)(void*)’

c++ - 如何将关键点复制到另一个 vector

c++ - 边缘检测 - 不良检测

c++ - 在这里进行 const 转换安全吗?

c++ - 从原始数据创建虚拟类

c++ - 将对象 vector 写入文件

C++,模板的非参数类型 : only const variables?

c++ - 用于编译和运行 C++ 的 bash 脚本

C++ vector 大小返回零

c++ - 内部类私有(private)成员访问和封闭的友好性