Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterators and reference counted strings

If we consider a std::string implementation that uses reference counting, consider this scenario:

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

What happens in L1 and L2? Is the reference counting broken and a deep copy is performed? I think so, but my concern says that if that occurs, doing a simple:

cout << german[1] << endl; 

or a simple:

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

in non-const contexts would perform unnecessary deep copies. Am I right? How do the implementations deal with this detail?

like image 449
ebasconp Avatar asked Jun 21 '12 23:06

ebasconp


2 Answers

You are correct, a copy would be made in all four examples (L1, L2, and the two below), even though for the latter two it's unnecessary.

Unfortunately when the non-const version of operator[] is called or a non-const iterator is dereferenced, there is no way for the implementation to tell whether or not the resulting non-const reference will be used to modify the object, so it has to play it safe and make a copy.

C++11 added functions cbegin() and cend() to strings and other containers which return const iterators even if called on a non-const object. This helps alleviate the problem. I'm not aware of a comparable solution for operator[].

Note: having operator[] or the iterator's operator*() return a proxy type, as some of the other answerers suggested, is not really an option because it breaks container requirements, one of which is that these functions return actual references. (This is why everyone now agrees that vector<bool> is a mistake - it uses proxies in this way).

(Of course, if you're writing your own reference-counted class, there's nothing stopping you from using proxy types to achieve this.)

like image 191
HighCommander4 Avatar answered Oct 21 '22 09:10

HighCommander4


One way to achieve this is through proxy classes. So when you index into a string instead if getting a char you get an object that looks and feels like a char. When a write is performed on it it causes deep copy on the original string.

like image 26
hawk Avatar answered Oct 21 '22 09:10

hawk