关于写时复制(copy-on-write)

 大部份的STL在实现string时,都采用COW来保证其高效性。即多个类会共用一个数据缓冲区(buffer),在拷贝构造、赋值等操作时,并不会对buffer进行复制。仅在需要对buffer进行修改,而且此buffer已与别的类共享了,才会开辟空间,将buffer复制一份进行修改。同样在析构时,如果buffer与与别的类共享,也不会释放空间。

例如:

#include <stdio.h>
#include <string>
using namespace std;

int main()
{
    string test1 = "hello";
    string test2(test1);

    printf("test1:%p test2:%p\n", test1.c_str(), test2.c_str());
}

运行结果:
引用:test1:0x90a9014 test2:0x90a9014

c_str()返回指向当前串的一个临时指针,是一个只读指针

可见两个地址是相等的,它们共用了同一个缓冲区。
什么时候会引起数据区的复制?当然是要修改string的值的时候。

#include <stdio.h>
#include <string>
using namespace std;

int main()
{
    string test1 = "hello";
    string test2(test1);

    printf("test1:%p test2:%p\n", test1.c_str(), test2.c_str());
    test2[0] = 'w';
    printf("test1:%p test2:%p\n", test1.c_str(), test2.c_str());
}


运行结果:
引用:
test1:0x9e85014 test2:0x9e85014
test1:0x9e85014 test2:0x9e8502c


可以看到test2发生了变化。
再进一步,编译如何确定程序要对buffer进行修改,从而去开辟新的空间呢?
程序一般是通过[]运算符、iterator去访问并修改数据。很自然地认为,对于左值会引起数据复制,而右值不会。但实际上,编译没这么做。可能是左值或右值的判定并没有那么简单吧?

#include <stdio.h>
#include <string>
using namespace std;

int main()
{
    string test1 = "hello";
    string test2(test1);

    printf("test1:%p   test2:%p\n", test1.c_str(), test2.c_str());
     printf("test1:%p   test2:%p\n", &test1[0], &test2[0]);
}


运行结果:
引用:
test1:0x8a4a014 test2:0x8a4a014
test1:0x8a4a014 test2:0x8a4a02c


test2发生了变化。
看一下源码:

const_reference
      operator[] (size_type __pos) const
      {
        _GLIBCXX_DEBUG_ASSERT(__pos <= size());
        return _M_data()[__pos];
      }

      reference
      operator[](size_type __pos)
      {
        _GLIBCXX_DEBUG_ASSERT(__pos < size());
        _M_leak();
        return _M_data()[__pos];
      }


也就是说判定是否可能有写操作是与类的类型相关的,如果是const string,则不复制,如果是string,则一定复制
再看看这个:

#include <stdio.h>
#include <string>
using namespace std;

int main()
{
    string test1 = "hello";
    string test2(test1);

    printf("test1:%p test2:%p\n", test1.c_str(), test2.c_str());
    const string &test3 = test1;
    const string &test4 = test2;
    printf("test1:%p test2:%p\n", &test3[0], &test4[0]);
}


结果就是:
引用:
test1:0x8c62014 test2:0x8c62014
test1:0x8c62014 test2:0x8c62014


当然这样写很难受,凭什么要搞两个const的引用出来啊?
这样就比较自然:

#include <stdio.h>
#include <string>
using namespace std;

void proc(const string& test1, const string& test2)
{
    printf("test1:%p test2:%p\n", &test1[0], &test2[0]);
}

int main()
{
    string test1 = "hello";
    string test2(test1);

    printf("test1:%p test2:%p\n", test1.c_str(), test2.c_str());
    proc(test1, test2);
}


也是说一定要严格地确定数据类型是否是const的,如果函数里不修改修,则传const,良好的习惯有利于代码质量的提高。
string和char *是无法共享数据区的,所以用c++就尽量少用指针,两种风格合在一起,效率是最低的。



转自 http://bbs.chinaunix.net/viewthread.php?tid=834292


 

写时复制Copy-on-Write,简称COW)策略是一种用于优化内存和时间效率的技术,常用于操作系统、数据库以及编程语言的实现中。 在COW策略中,当多个进程或线程共享同一份资源或数据时,不会立即复制这份资源或数据,而是共享同一份拷贝,只有在某个进程或线程需要修改这份数据时才会执行实际的复制操作。 具体来说,在资源或数据被多个进程或线程共享时,它们实际上共享同一份只读的拷贝。当某个进程或线程需要修改这份数据时,会先执行一次复制操作,然后修改复制后的数据,而其他进程或线程仍然共享原始的只读拷贝。这样一来,当需要修改的进程或线程比较少时,就可以避免大规模的复制操作,从而提高内存和时间效率。 COW策略的优点在于减少了复制操作的开销,节省了内存的使用。当多个进程或线程共享大规模数据时,COW可以避免大规模的数据复制,减少内存的占用,从而减少了系统开销。同时,COW也提高了并发性,因为不需要加锁来保护原始拷贝的数据,只有在修改时才需要加锁。 然而,COW策略也存在一些缺点。首先,每次数据修改都需要复制一份数据,而且当修改操作频繁时,复制操作的开销可能逐渐积累起来,降低了效率。此外,COW策略的实现也较为复杂,需要额外的开销和处理逻辑。 总之,COW策略是一种用于优化内存和时间效率的技术,通过延迟实际的数据复制操作,同时共享同一份只读数据拷贝,从而提高系统的性能和并发性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值