Почему строки VC++ не учитываются?

Стандарт 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 была ошибка, в которой реализована не-поточная реализация подсчета ссылок, что приводило к случайным программным сбоям. Это причина? Они просто боятся использовать повторный подсчет, даже если это обычная практика? Они предпочитают вообще не использовать реф-счет для решения проблемы?

Спасибо

5 ответов

Я думаю, что все больше и больше std::string реализации отойдут от пересчета / копирования при записи, поскольку это часто встречная оптимизация в многопоточном коде.

См. Статью Херба Саттера " Оптимизации, которых нет" (в многопоточном мире).

Фактическая STL требует, чтобы при использовании подсчета ссылок семантика была такой же, как и для версии без подсчета ссылок. Это не тривиально для общего случая.(Вот почему вы не должны писать свой класс on string).

Из-за следующей ситуации:

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 для получения более подробной информации

Как заявили Martin & Michael, Copy On Write (COW) часто доставляет больше хлопот, чем стоит, для дальнейшего чтения посмотрите эту превосходную статью Келвина Хенни о Mad COW Disease, и я считаю, что именно Андрей Александреску заявил, что Small String Optimization работает лучше во многих приложениях (но я не могу найти статью).

Оптимизация малых строк - это то, где вы увеличиваете строковый объект и избегаете выделения кучи для маленьких строк. Реализация игрушек будет выглядеть примерно так:

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 
    }
    // ...
};

Возможно, Microsoft определила, что копирование строк не было большой проблемой, так как почти весь код C++ использует передачу по ссылке везде, где это возможно. Поддержание счетчика ссылок имеет накладные расходы в пространстве и времени (игнорируя блокировку), которые, возможно, они решили, что не стоит платить.

А может и нет. Если это вас беспокоит, вы должны профилировать свое приложение, чтобы определить, является ли копирование строки серьезными накладными расходами и переключено ли оно на другую реализацию строки.

Это не главная причина, но я видел много неверного кода на платформе win32, который делает что-то вроде const_cast< char* >( str.c_str() ),

Может быть, Microsoft знает об этом и заботится о разработчиках:)

Другие вопросы по тегам