Почему строки в std::vector<std::string> заканчиваются тем же адресом данных?

Рассмотрим следующую программу C++:

#include <iostream>
#include <string>
#include <vector>


int main()
{
    std::vector<std::string> v(2, std::string(24,0));
    for (auto& s : v) {
        std::cout << "Address: " << (void*)s.data() << std::endl;
    }
}

Demo

Я ожидал бы, что каждая строка в векторе будет указывать на другую область памяти, но при компиляции с -D_GLIBCXX_USE_CXX11_ABI=0 при использовании gcc 6.3.0 и 8.2.1 они показывают один и тот же адрес. (при компиляции без флага они показывают разные адреса). Почему это?

Ответ 1

-D_GLIBCXX_USE_CXX11_ABI=0 (1) с этим std::string использует стратегию COW, которая была разрешена до С++ 11.

C opy O n W - это стратегия оптимизации. С COW, когда несколько объектов std::strings создаются с одним и тем же значением, будет создан только один базовый строковый массив, и все объекты будут указывать на него. Это то, что вы наблюдаете в своем коде. При записи в один из объектов будет создана копия массива строк, уникальная для этого объекта std::string, а затем она будет изменена.

Начиная с С++ 11 эта стратегия недопустима (2), и большинство реализаций теперь используют вместо этого оптимизацию SSO (Short String Optimization) для std::string.


(1) Общие сведения о GCC 5 _GLIBCXX_USE_CXX11_ABI или новом ABI

(2) Легальность реализации COW std::string в С++ 11