2012-06-21 3 views
7

Если мы рассмотрим реализацию станд :: строка, которая использует подсчет ссылок, рассмотрим следующий сценарий:итераторы и ссылки подсчитывали строки

int main() 
{ 
    string english = "Hello"; 
    string german = english; //refcnt = 2 
    string german2 = german; 

    /* L1 */ german[1] = 'a'; 
    /* L2 */ *(german2.begin() + 1) = 'A'; 

    cout << english << endl << german << endl << german2 << endl; 
    return 0; 
} 

Что происходит в L1 и L2? Выполняется ли подсчет ссылок и выполняется глубокая копия? Я думаю, что это так, но мое беспокойство говорит, что если это произойдет, делая простой:

cout << german[1] << endl; 

или просто:

cout << *(german.begin()) << endl; 

в неконстантных контекстах будет выполнять ненужные глубокие копии. Я прав? Каким образом реализации имеют дело с этой деталью?

+0

Это одна из причин, почему подсчет ссылок 'STD :: string's не так популярны. Это не работает вообще, как первоначально предполагалось. –

ответ

6

Вы верны, копия будет сделана во всех четырех примерах (L1, L2 и два ниже), хотя для последних двух это не нужно.

К сожалению, когда вызывается неконстантная версия оператора [] или неконстантный итератор, не существует способа для реализации, чтобы определить, будет ли полученная неконстантная ссылка использоваться для изменения объект, поэтому он должен играть в нее безопасно и делать копию.

C++ 11 добавлены функции cbegin() и cend() к строкам и другим контейнерам, которые возвращают константные итераторы, даже если вызываются на неконстантный объект. Это помогает устранить проблему. Я не знаю сопоставимого решения для оператора [].

Примечание: оператор operator [] или оператор итератора *() возвращают прокси-тип, как это было предложено некоторыми другими респондентами, поскольку это нарушает требования контейнера, одним из которых является то, что эти функции возвращают действительные Рекомендации. (Вот почему все теперь согласны с тем, что ошибка vector<bool> - так использует прокси).

(Конечно, если вы пишете свой собственный эталонный подсчет класс, там ничего не мешает вам использовать типы прокси-сервер для достижения этой цели.)

2

Один из способов достижения этого - через классы прокси. Поэтому, когда вы индексируете строку вместо этого, если вы получаете символ, вы получаете объект, который выглядит и чувствует себя как символ. Когда на нем выполняется запись, он вызывает глубокую копию исходной строки.

Смежные вопросы