14

STL 标准不要求从 std::string 被引用。但事实上,大多数 C++ 实现都提供了引用计数、写入时复制的字符串,允许您将字符串作为原始类型按值传递。此外,这些实现(至少 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 中有一个错误,它具有非线程安全的引用计数实现,导致随机程序崩溃。这是原因吗?他们只是害怕再使用引用计数,即使这是常见的做法?他们宁愿完全不使用引用计数来解决问题?

谢谢

4

5 回答 5

22

我认为越来越多的std::string实现将远离引用计数/写时复制,因为它通常是多线程代码中的反优化。

请参阅 Herb Sutter 的文章优化不是(在多线程世界中)

于 2009-04-01T19:40:38.187 回答
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了解更多详情

于 2009-04-01T19:59:00.637 回答
7

正如 Martin 和 Michael 所说,写时复制 (COW) 往往比它的价值更麻烦,要进一步阅读,请参阅Kelvin Henney撰写的这篇关于疯狂牛病的优秀文章,我相信是Andrei Alexandrescu小字符串优化表现更好在许多应用程序中(但我找不到文章)。

小字符串优化是您使字符串对象更大并避免小字符串的堆分配的地方。玩具实现看起来像这样:

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 
    }
    // ...
};
于 2009-04-02T19:01:11.713 回答
5

也许微软认为字符串复制不是一个大问题,因为几乎所有 C++ 代码都尽可能使用通过引用传递。维护一个引用计数在空间和时间上有开销(忽略锁定),也许他们认为不值得付出。

或者可能不是。如果您对此感到担忧,您应该分析您的应用程序以确定字符串复制是否是主要开销,以及是否切换到不同的字符串实现。

于 2009-04-01T19:43:40.877 回答
1

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

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

于 2009-04-01T19:46:18.330 回答