六一的部落格


关关难过关关过,前路漫漫亦灿灿。



标准库提供了swap操作, 模板函数

我们也可以为类定义swap操作, 作为类的友元

对类类型调用swap操作时, 自定义swap的匹配优先级高于标准库提供的swap

swap不是必要的, 但对于分配了资源的类, 可作为一种很重要的优化手段


比较拷贝赋值和交换操作

  1. 拷贝赋值: 需要一次拷贝和两次赋值

    1Foo a, b;
    2Foo temp = a;
    3a = b;
    4b = temp;
  2. 交换操作: 可以减少内存分配

    1Foo a, b;
    2swap(a, b);

为HasPtr的类值版本实现swap操作

 1class HasPtr
 2{
 3    friend void swap(HasPtr &, HasPtr &);
 4public:
 5    HasPtr(const string &s = string()) : ps(new string(s)), i(0) { }
 6    HasPtr(const HasPtr &p) : ps(new string(*p.ps), i(p.i)) { }
 7    HasPtr &operator=(const HasPtr &);
 8    ~HasPtr() { delete ps; }
 9
10private:
11    string *ps;
12    int i;
13};
14
15HasPtr &HasPtr::operator=(const HasPtr &rhs)
16{
17    auto newp = new string(*rhs.ps);
18    delete ps;
19    ps = newp;
20    i = rhs.i;
21
22    return *this;
23}
24
25inline void swap(HasPtr &lhs, HasPtr &rhs)
26{
27    swap(lhs.ps, rhs.ps);
28    swap(lhs.i, rhs.i);
29}

在赋值运算符中使用swap

第3种赋值运算符重载

定义了swap的类通常用swap来定义他们的赋值运算符, 可以将这种重载方式描述为拷贝并交换 copy and swap

  1. 使用右侧运算对象拷贝初始化rhs, 其拥有动态内存, 且一定不同于 *this
  2. 完成交换后, this拥有rhs的动态内存空间, 是新分配的
  3. 函数结束后, 析构函数销毁rhs, 释放this的原动态内存

自动处理了自赋值情况, 且天然异常安全

1HasPtr &HasPtr::operator=(HasPtr rhs)
2{
3    swap(*this, rhs);
4    return *this;
5}

异常安全: 发生异常时不影响原对象


拷贝赋值运算符: 使用swap操作


标准库提供了swap操作, 模板函数

我们也可以为类定义swap操作, 作为类的友元

对类类型调用swap操作时, 自定义swap的匹配优先级高于标准库提供的swap

swap不是必要的, 但对于分配了资源的类, 可作为一种很重要的优化手段


比较拷贝赋值和交换操作

  1. 拷贝赋值: 需要一次拷贝和两次赋值

    1Foo a, b;
    2Foo temp = a;
    3a = b;
    4b = temp;
  2. 交换操作: 可以减少内存分配

    1Foo a, b;
    2swap(a, b);

为HasPtr的类值版本实现swap操作

 1class HasPtr
 2{
 3    friend void swap(HasPtr &, HasPtr &);
 4public:
 5    HasPtr(const string &s = string()) : ps(new string(s)), i(0) { }
 6    HasPtr(const HasPtr &p) : ps(new string(*p.ps), i(p.i)) { }
 7    HasPtr &operator=(const HasPtr &);
 8    ~HasPtr() { delete ps; }
 9
10private:
11    string *ps;
12    int i;
13};
14
15HasPtr &HasPtr::operator=(const HasPtr &rhs)
16{
17    auto newp = new string(*rhs.ps);
18    delete ps;
19    ps = newp;
20    i = rhs.i;
21
22    return *this;
23}
24
25inline void swap(HasPtr &lhs, HasPtr &rhs)
26{
27    swap(lhs.ps, rhs.ps);
28    swap(lhs.i, rhs.i);
29}

在赋值运算符中使用swap

第3种赋值运算符重载

定义了swap的类通常用swap来定义他们的赋值运算符, 可以将这种重载方式描述为拷贝并交换 copy and swap

  1. 使用右侧运算对象拷贝初始化rhs, 其拥有动态内存, 且一定不同于 *this
  2. 完成交换后, this拥有rhs的动态内存空间, 是新分配的
  3. 函数结束后, 析构函数销毁rhs, 释放this的原动态内存

自动处理了自赋值情况, 且天然异常安全

1HasPtr &HasPtr::operator=(HasPtr rhs)
2{
3    swap(*this, rhs);
4    return *this;
5}

异常安全: 发生异常时不影响原对象