首页 > 其他分享 >copy-and-swap

copy-and-swap

时间:2023-11-11 20:33:21浏览次数:27  
标签:std sz dst swap CharStore copy store

copy-and-swap 为C++中的惯用法,用于在拷贝赋值函数中保证对象完整性, 提供异常保证,以代码为例【1】:

class CharStore {
public:
    CharStore(std::size_t size = 0):
        sz(size),
        store(std::make_unique<char[]>(sz)) {}
    // Copy-constructor
    CharStore(const CharStore& other):
        sz(other.sz),
        store(std::make_unique<char[]>(sz)){
            std::copy(other.store.get(), other.store.get() + sz, store.get());
    }
    // Copy-assignment
    CharStore& operator=(const CharStore& other) {
        // 1. prevent self-assignment
        if (this != &other) {
            // 2. delete old data
            store.reset();
            // 3.0 prepare to assign new data
            sz = other.sz; 
            // 3.1 create storage for assignment
            store = std::make_unique<char[]>(sz);
            // 3.2 assign new data
            std::copy(other.store.get(), other.store.get() + sz, store.get()); 
        } 
        return *this;
    }

        
    void copyStr(char const *p, size_t len) {
        auto dst = store.get();
        for (size_t i = 0; i < len; ++i) {
            dst[i] = p[i];
        }

    }

    void print() {
        auto arr = store.get();
        for (size_t i = 0; i < sz; ++i)
            std::cout <<  arr[i];
        std::cout << std::endl;
    }

    ~CharStore() {}
private:
    std::size_t sz;
    std::unique_ptr<char[]> store;
};

int main() 
{
    CharStore src(14);
    CharStore dst(14);
    char const *a = "This is test";
    char const *b = "That is test";
    src.copyStr(a, 13);
    dst.copyStr(b, 13);
    src.print();
    dst.print();

    dst = src;
    dst.print();
}

当拷贝赋值进行深拷贝时,释放了目的对象dst中的store指针,此时如果3.1步骤中make_unique失败抛出异常,导致拷贝赋值失败,而dst中store已经不可用;

而copy-and-swap提供了一种解决办法,修改上述代码为:

class CharStore {
public:
    CharStore(std::size_t size = 0):
        sz(size),
        store(std::make_unique<char[]>(sz)) {}
    // Copy-constructor
    CharStore(const CharStore& other):
        sz(other.sz),
        store(std::make_unique<char[]>(sz)){
            std::copy(other.store.get(), other.store.get() + sz, store.get());
    }
    // Copy-assignment
    CharStore& operator=(const CharStore& other) {
        CharStore temp(other);
        temp.swap(*this);
        return *this;
    }
    // Non-throwing swap function
    void swap(CharStore& second) {
        using std::swap;
        swap(sz, second.sz);
        swap(store, second.store);
    }
    
    void copyStr(char const *p, size_t len) {
        auto dst = store.get();
        for (size_t i = 0; i < len; ++i) {
            dst[i] = p[i];
        }
    }

    void print() {
        auto arr = store.get();
        for (size_t i = 0; i < sz; ++i)
            std::cout <<  arr[i];
        std::cout << std::endl;
    }

    ~CharStore() {}
private:
    std::size_t sz;
    std::unique_ptr<char[]> store;
};

int main() 
{
    CharStore src(14);
    CharStore dst(14);
    char const *a = "This is test";
    char const *b = "That is test";
    src.copyStr(a, 13);
    dst.copyStr(b, 13);
    src.print();
    dst.print();

    dst = src;
    dst.print();
}

CharStore引入swap函数,在拷贝赋值函数中先引入了temp临时对象,再将temp对象与dst对象进行swap;

此时如果临时对象由于异常创建失败,则不会影响dst对象的有效性;

此处通过using std::swap引入标准库中的swap函数:

void swap(CharStore& second) {
        using std::swap;
        swap(sz, second.sz);
        swap(store, second.store);
    }

如果需要swap的对象实现了自己的 swap 版本,则可用调用自己实现的版本,这里应用ADL进行匹配,可参见【2】中介绍,引用【3】的示例代码:

namespace Ns
{
    class A
    {
        int id{};
 
        friend void swap(A& lhs, A& rhs)
        {
            std::cout << "swap(" << lhs << ", " << rhs << ")\n";
            std::swap(lhs.id, rhs.id);
        }
 
        friend std::ostream& operator<< (std::ostream& os, A const& a)
        {
            return os << "A::id=" << a.id;
        }
 
    public:
        A(int i) : id{i} {}
        A(A const&) = delete;
        A& operator = (A const&) = delete;
    };
}
 
int main()
{
    int a = 5, b = 3;
    std::cout << a << ' ' << b << '\n';
    std::swap(a, b);
    std::cout << a << ' ' << b << '\n';
 
    Ns::A p{6}, q{9};
    std::cout << p << ' ' << q << '\n';
    // std::swap(p, q);  // 错误,不满足类型要求
    swap(p, q);       // OK:通过ADL找到类内定义的swap函数
    std::cout << p << ' ' << q << '\n';
}

参考资料

【1】https://www.educative.io/answers/what-is-the-copy-and-swap-idiom-in-cpp

【2】C++ ADL & CPO介绍

【3】https://zh.cppreference.com/w/cpp/algorithm/swap

标签:std,sz,dst,swap,CharStore,copy,store
From: https://blog.51cto.com/u_13137973/8319482

相关文章

  • 无涯教程-批处理 - Copying Registry Keys函数
    通过REGCOPY命令从注册表中复制,请注意,为了从注册表复制值,您需要在系统上具有足够的特权才能在源位置和目标位置上都执行此操作。REGCOPY[\\SourceMachine\][ROOT\]RegKey[\\DestMachine\][ROOT\]RegKey@echooffREGCOPYHKEY_CURRENT_USER\ConsoleHKEY_CURRENT_USER\Co......
  • 去中心化交易所swap系统开发
    去中心化交易所软件系统平台,允许用户数字化的交易,无需传统的交易方式,进行各种证件的限制。而这样Swap系统软件部分是DEX的组合,它允许用户轻松的实现不同类型的交易。Swap系统软件开发涉及多个领域,不仅限于交易管理,流水管理,智能化合约管理,以下几个关键性因素:1.交易对管理:Swap系统......
  • CF1485F Copy or Prefix Sum 题解
    思路考虑\(a_i\)要么是\(b_i\)要么是\(b_i-s\)。考虑\(s\)代表着什么。它是\(a\)的前缀和。那么必然是往前一段\(b\)的和。因为每个\(b\)代表着要么是这一位的\(a\)或者前面所有的\(a\)。考虑设\(f_i\)为这个位置填\(b_i\)的方案数。\(g_i\)为这个......
  • CF1485E Move and Swap 题解
    不要什么脑子的带\(log\)做法。思路考虑\(dp_{i,j}\)表示红点到\(i\),蓝点到\(j\)的最大权值。那么有:\[dp_{i,j}=\max(dp_{fa_i,pre},dp_{fa_j,pre})+|a_i-a_j|\]其中\(pre\)是任意一个上一层节点。发现第二维没有用。可以优化:\[dp_i=\max(dp_{fa_i}+\max(|a_i-a_......
  • Spring BeanUtils.copyProperties简化写法
    代码importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importorg.springframework.beans.BeanUtils;importorg.springframework.beans.BeansException;importorg.springframework.util.StopWatch;publicclassBeanUtils2{......
  • 线程安全集合(JDK1.5之前和之后)、CopyOnWriteArrayList、CopyOnWriteArraySet
    JDK1.5之前JDK1.5之前:Collections.synchronizedList JDK1.5之后CopyOnWriteArrayList   CopyOnWriteArraySet    ......
  • Dockerfile中'COPY'和'ADD'命令的区别是什么?
    内容来自DOChttps://q.houxu6.top/?s=Dockerfile中'COPY'和'ADD'命令的区别是什么?Dockerfile中COPY和ADD命令的区别是什么,以及何时使用其中一个而不是另一个?COPY<src><dest>COPY指令将从<src>复制新文件,并将它们添加到容器的文件系统路径<dest>。ADD<src><dest>......
  • JUC高并发容器-CopyOnWriteArrayList
    CopyOnWriteArrayListJUC高并发容器线程安全的同步容器类什么是高并发容器?CopyOnWriteArrayListJUC高并发容器线程安全的同步容器类  Java同步容器类通过Synchronized(内置锁)来实现同步的容器,比如Vector、HashTable以及SynchronizedList等容器。线程安全的同步容器类主要有Vec......
  • 【IC 文案编辑排版软件】InCopy CC2018 for Mac 中文汉化版下载
    AdobeInCopyCC2018forMac中文汉化版是Adobe公司发布的一款专业的文案编辑排版软件,简称ICCC2018Mac版。AdobeInCopyCC2018采用了更加现代化的UI设计,并且增加了对HIDPI和视网膜显示屏的支持,增强了字体搜索功能和灵活的页面访问,更加精确字数,随心同步字体,提高工作效率。软件......
  • org.apache.subversion.javahl.ClientException: The working copy needs to be upgra
    eclipse不编译,每次修改代码控制台都显示错误svn:Theworkingcopyneedstobeupgradedorg.apache.subversion.javahl.ClientException:Theworkingcopyneedstobeupgradedsvn:Workingcopy‘E:\aliyun-spirit\spiritmap0916′istooold(format10,createdbySubversi......