标签: copy-and-swap

什么是四(一半)?

为了正确处理对象复制,经验法则是三规则.使用C++ 11,移动语义是一个东西,所以它是五条规则.然而,在这里和互联网上的讨论中,我也看到了对四条规则(一半)的引用,它是五条规则和复制交换习语的组合.

究竟是什么(四分之一)呢?需要实现哪些功能,每个功能的主体应该是什么样的?一半的功能是什么?与五法则相比,这种方法有任何缺点或警告吗?

这是一个类似于我当前代码的参考实现.如果这不正确,那么正确的实现会是什么样的?

//I understand that in this example, I could just use `std::unique_ptr`.
//Just assume it's a more complex resource.
#include <utility>

class Foo {
public:
    //We must have a default constructor so we can swap during copy construction.
    //It need not be useful, but it should be swappable and deconstructable.
    //It can be private, if it's not truly a valid state for the object.
    Foo() : resource(nullptr) {}

    //Normal …
Run Code Online (Sandbox Code Playgroud)

c++ copy-constructor assignment-operator copy-and-swap c++11

15
推荐指数
2
解决办法
2120
查看次数

何时复制和交换习语不适用

看完有关的复制和交换成语我读过这个这下称(2):

class_name & class_name :: operator= ( const class_name & )     (2)     
Run Code Online (Sandbox Code Playgroud)

(2)当不能使用复制和交换习语时,复制赋值运算符的典型声明

我们何时应该避免使用复制和交换习惯用法?

什么时候"完全不能使用"?

是否有现实生活中的情况,即复制和交换以及零规则都不适用?

我确实找到了这个问题,但它过于具体,没有包含任何关于如何识别此类案例的指南.

c++ copy-and-swap

13
推荐指数
1
解决办法
904
查看次数

重用复制和交换习语

我正在尝试将复制和交换习惯用法放入可重用的混音中:

template<typename Derived>
struct copy_and_swap
{
    Derived& operator=(Derived copy)
    {
        Derived* derived = static_cast<Derived*>(this);
        derived->swap(copy);
        return *derived;
    }
};
Run Code Online (Sandbox Code Playgroud)

我打算通过CRTP混合:

struct Foo : copy_and_swap<Foo>
{
    Foo()
    {
        std::cout << "default\n";
    }

    Foo(const Foo& other)
    {
        std::cout << "copy\n";
    }

    void swap(Foo& other)
    {
        std::cout << "swap\n";
    }
};
Run Code Online (Sandbox Code Playgroud)

但是,一个简单的测试显示它不起作用:

Foo x;
Foo y;
x = y;
Run Code Online (Sandbox Code Playgroud)

这仅打印两次"默认",不打印"复制"或"交换".我在这里错过了什么?

c++ mixins crtp assignment-operator copy-and-swap

11
推荐指数
2
解决办法
779
查看次数

复制和交换习语的效率低下?

我正在测试一些代码,其中std::vector一个类中有一个数据成员.类是既可以复印活动,并operator=描述实现这里使用复制和交换成语.

如果有两个vectors,比如v1大容量和v2小容量,并被v2复制到v1(v1 = v2),v1在分配后保留大容量 ; 这是有道理的,因为下一次v1.push_back()调用不必强制新的重新分配(换句话说:释放已经可用的内存,然后重新分配它来增长向量没有多大意义).

但是,如果对具有as数据成员的进行相同的赋值vector,则行为不同,并且在赋值之后保留更大的容量.

如果使用复制operator=和交换习惯用法,并且复制和移动operator=分开实现的,那么行为就像预期的那样(对于普通的非成员vectors).

这是为什么?我们是否应该遵循复制和交换习惯用法,而是分别实施operator=(const X& other)(复制 op=)和operator=(X&& other)(移动 op=)以获得最佳性能?

这是一个可重复的测试输出与复制和交换成语(注意如何在这种情况下,之后 x1 = x2,x1.GetV().capacity()就是1000,不1,000,000):

C:\TEMP\CppTests>cl /EHsc …
Run Code Online (Sandbox Code Playgroud)

c++ performance vector copy-and-swap c++11

10
推荐指数
2
解决办法
1290
查看次数

安全分配和复制交换习语

我正在学习c ++,最近我学习了(这里是堆栈溢出)有关复制和交换的习惯用法,我对它有一些问题.所以,假设我有以下类使用复制和交换习惯用法,例如:

class Foo {
private:
  int * foo;
  int size;

public:
  Foo(size_t size) : size(size) { foo = new int[size](); }
  ~Foo(){delete foo;}

  Foo(Foo const& other){
    size = other.size;
    foo = new int[size];
    copy(other.foo, other.foo + size, foo);
  }

  void swap(Foo& other) { 
    std::swap(foo,  other.foo);  
    std::swap(size, other.size); 
  }

  Foo& operator=(Foo g) { 
    g.swap(*this); 
    return *this; 
  }

  int& operator[] (const int idx) {return foo[idx];}
};
Run Code Online (Sandbox Code Playgroud)

我的问题是,假设我有另一个类,它有一个Foo对象作为数据但没有指针或其他可能需要自定义复制或赋值的资源:

class Bar {
private:
  Foo bar;
public:
  Bar(Foo foo) : bar(foo) {};
  ~Bar(){};
  Bar(Bar …
Run Code Online (Sandbox Code Playgroud)

c++ class copy-constructor rule-of-three copy-and-swap

9
推荐指数
2
解决办法
2114
查看次数

使用纯虚拟类复制和交换习语

我正在尝试使用纯虚方法和'复制和交换'惯用法实现虚拟类,但我遇到了一些问题.代码将无法编译,因为我在包含纯虚方法的类A的assign运算符中创建实例.

有没有办法如何使用纯虚方法和复制和交换成语?

class A
{
public:
    A( string name) :
            m_name(name) { m_type = ""; }
    A( const A & rec) :
            m_name(rec.m_name), m_type(rec.m_type) {}
    friend void swap(A & lhs, A & rhs)
    {
        std::swap(lhs.m_name, rhs.m_name);
        std::swap(lhs.m_type, rhs.m_type);
    }

    A & operator=( const A & rhs)
    {
        A tmp(rhs); 
        swap(*this, tmp);
        return *this;
    }

    friend ostream & operator<<( ostream & os,A & x)
    {
         x.print(os);
         return os;
    }

protected:
    virtual void print(ostream & os) =0;    

    string m_type;
    string m_name;
}; …
Run Code Online (Sandbox Code Playgroud)

c++ virtual class copy-and-swap

7
推荐指数
1
解决办法
882
查看次数

通过复制和交换与两个锁分配

借用Howard Hinnant的例子并将其修改为使用copy-and-swap,这是op =线程安全吗?

struct A {
  A() = default;
  A(A const &x);  // Assume implements correct locking and copying.

  A& operator=(A x) {
    std::lock_guard<std::mutex> lock_data (_mut);
    using std::swap;
    swap(_data, x._data);
    return *this;
  }

private:
  mutable std::mutex _mut;
  std::vector<double> _data;
};
Run Code Online (Sandbox Code Playgroud)

我相信这个线程安全(记住op =的参数是通过值传递的),我能找到的唯一问题是在地毯下扫描的那个:复制ctor.但是,它是一种罕见的类,它允许复制赋值而不是复制构造,因此在两种选择中都存在同样的问题.

鉴于自我分配是如此罕见(至少在这个例子中)我不介意额外的副本如果发生,考虑这个!=&rhs的潜在优化要么可以忽略不计,要么是悲观化.与原始策略(下面)相比,是否还有其他理由更喜欢或避免它?

A& operator=(A const &rhs) {
  if (this != &rhs) {
    std::unique_lock<std::mutex> lhs_lock(    _mut, std::defer_lock);
    std::unique_lock<std::mutex> rhs_lock(rhs._mut, std::defer_lock);
    std::lock(lhs_lock, rhs_lock);
    _data = rhs._data;
  }
  return *this;
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我认为这简洁地处理了复制文件,至少在本课程中,即使它有点迟钝:

A(A const &x) : _data {(std::lock_guard<std::mutex>(x._mut), x._data)} {}
Run Code Online (Sandbox Code Playgroud)

c++ mutex copy-and-swap c++11

6
推荐指数
1
解决办法
1816
查看次数

'operator ='的模糊重载与c ++ 11 std :: move和copy and swap idiom

我收到以下错误:

[matt ~] g++ -std=c++11 main.cpp -DCOPY_AND_SWAP && ./a.out
main.cpp: In function ‘int main(int, const char* const*)’:
main.cpp:101:24: error: ambiguous overload for ‘operator=’ in ‘move = std::move<Test&>((* & copy))’
main.cpp:101:24: note: candidates are:
main.cpp:39:7: note: Test& Test::operator=(Test)
main.cpp:52:7: note: Test& Test::operator=(Test&&)
Run Code Online (Sandbox Code Playgroud)

编译以下代码时:

#include <iostream>
#include <unordered_map>
class Test final {
public:
  typedef std::unordered_map<std::string, std::string> Map;
public:
  Test();
  explicit Test(Map&& map);
  ~Test();
  Test(const Test& other);
  Test(Test&& test);
#ifdef COPY_AND_SWAP
  Test& operator=(Test other);
#else
  Test& operator=(const Test& other);
#endif
  Test& operator=(Test&& other); …
Run Code Online (Sandbox Code Playgroud)

c++ operator-overloading overload-resolution copy-and-swap c++11

6
推荐指数
1
解决办法
1947
查看次数

为什么SGI STL不使用复制和交换习惯用法?

我最近在StackOverflow上读到了关于什么是复制和交换习语的答案并且知道复制和交换习语可以

避免代码重复,并提供强大的异常保证.

但是,当我查看SGI STL deque 实现时,我发现它没有使用这个成语.我想知道为什么不,如果成语在某种程度上像一个"最佳实践"?

  deque& operator= (const deque& __x) {
    const size_type __len = size();
    if (&__x != this) {
      if (__len >= __x.size())
        erase(copy(__x.begin(), __x.end(), _M_start), _M_finish);
      else {
        const_iterator __mid = __x.begin() + difference_type(__len);
        copy(__x.begin(), __mid, _M_start);
        insert(_M_finish, __mid, __x.end());
      }
    }
    return *this;
  }       
Run Code Online (Sandbox Code Playgroud)

c++ stl copy-and-swap

6
推荐指数
1
解决办法
193
查看次数

在可移动和不可复制的类上使用移动和交换习惯是否有意义

如果我有一个类如

class Foo{
public:
    Foo(){...}
    Foo(Foo && rhs){...}
    operator=(Foo rhs){ swap(*this, rhs);}
    void swap(Foo &rhs);
private:
    Foo(const Foo&);
// snip: swap code
};
void swap(Foo& lhs, Foo& rhs);
Run Code Online (Sandbox Code Playgroud)

如果我没有复制构造函数,是否有意义实现operator = by value和swap?它应该防止复制我的类对象Foo但允许移动.

这个类是不可复制的,所以我不能复制构造或复制分配它.

编辑

我用这个测试了我的代码,它似乎有我想要的行为.

#include <utility>
#include <cstdlib>
using std::swap;
using std::move;
class Foo{
public: Foo():a(rand()),b(rand()) {}
        Foo(Foo && rhs):a(rhs.a), b(rhs.b){rhs.a=rhs.b=-1;}
        Foo& operator=(Foo rhs){swap(*this,rhs);return *this;}
        friend void swap(Foo& lhs, Foo& rhs){swap(lhs.a,rhs.a);swap(lhs.b,rhs.b);}
private:
    //My compiler doesn't yet implement deleted constructor
    Foo(const Foo&);
private:
    int a, b;
};

Foo …
Run Code Online (Sandbox Code Playgroud)

c++ rvalue-reference assignment-operator copy-and-swap c++11

5
推荐指数
1
解决办法
1829
查看次数