为什么VC ++字符串不被引用计数?

时间:2009-04-01 19:33:00

标签: c++ string visual-c++ reference-counting copy-on-write

STL标准不要求从std :: string中重新计算。但实际上大部分是C ++ 实现提供refcounted,copy-on-write字符串,允许您传递 string by value作为基本类型。这些实现(至少g ++)也使用 原子操作使这些字符串无锁且线程安全。

简易测试显示写时复制语义:

#include <iostream>
#include <string>

using namespace std;

void foo(string s)
{
    cout<<(void*)s.c_str()<<endl;
    string ss=s;
    cout<<(void*)ss.c_str()<<endl;
    char p=ss[0];
    cout<<(void*)ss.c_str()<<endl;
}

int main()
{
    string s="coocko";
    cout<<(void*)s.c_str()<<endl;
    foo(s);
    cout<<(void*)s.c_str()<<endl;
}

在使用非常量成员后,只有两个地址完全打印出来。

我使用HP,GCC和Intel编译器测试了此代码,并获得了类似的结果 - 字符串 作为写时复制容器工作。

另一方面,VC ++ 2005清楚地表明每个字符串都是完全复制的。

为什么吗

我知道VC ++ 6.0中存在一个非线程安全实现的错误 导致随机程序崩溃的引用计数。这是什么原因?他们只是 害怕再使用ref-count甚至是常见做法?他们宁愿不这样做 使用重新计算来解决问题?

由于

5 个答案:

答案 0 :(得分:22)

我认为越来越多的std::string实现将远离refcounting / copy-on-write,因为它通常是多线程代码中的反优化。

参见Herb Sutter的文章Optimizations That Aren't (In a Multithreaded World)

答案 1 :(得分:11)

STL实际要求如果使用引用计数,则语义与非引用计数版本相同。这对于一般情况来说并非无足轻重。(这就是为什么你不应该写你的字符串类)。

由于以下情况:

std::string   x("This is a string");
char&         x5 = x[5];
std::string   y(x);

x5 = '*';

有关详细信息,请参阅:http://www.sgi.com/tech/stl/string_discussion.html

答案 2 :(得分:7)

正如Martin&amp; Michael,Copy On Write(COW)通常比它的价值更麻烦,为了进一步阅读,请参阅 Kelvin Henney 关于Mad COW Disease的优秀文章,我相信它是 Andrei Alexandrescu < / em>表示小字符串优化在许多应用程序中表现更好(但我找不到文章)。

小字符串优化是使字符串对象更大并避免小字符串堆分配的地方。玩具实现将如下所示:

class string {
    char *begin_, *end_, *capacity_;
    char buff_[64]; // pick optimal size (or template argument)
public:
    string(const char* str)
    {
        size_t len = strlen(str);
        if (len < sizeof(buff_))
        {
            strcpy(buff_, str);
            begin_ = buff_;
            capacity_ = buff_ + sizeof(buff_);
        }
        else
        {
            begin_ = strdup(str);
            capacity_ = begin_ + len;
        }
        end_ = begin_+len;
    }

    ~string()
    {
        if (begin_ != buff_)
            free(begin_); // strdup requires free 
    }
    // ...
};

答案 3 :(得分:5)

也许Microsoft确定字符串复制不是一个大问题,因为几乎所有的C ++代码都尽可能使用传递引用。维护引用计数会占用空间和时间(忽略锁定),这可能是他们认为不值得付费的。

或许不是。如果您对此感兴趣,则应分析应用程序以确定字符串复制是否是主要开销,以及是否切换到其他字符串实现。

答案 4 :(得分:1)

这不是主要原因,但我在win32平台下看到了许多不正确的代码,它们执行const_cast< char* >( str.c_str() )之类的操作。

也许微软知道这一点并关心开发人员:)