为什么从std::string的initializer列表中填充std::向量不会调用std::字符串构造函数

Why does filling a std::vector from an initilizer list of std::string does not call std::string constructor

本文关键字:std 向量 字符串 构造函数 填充 调用 列表 string initializer 为什么      更新时间:2023-10-16

我有以下类:

class StringContainer {
  public:
    StringContainer(const std::string& s1, const std::string& s2) {  
      string_array_ = {s1, s2};
    }
  std::vector<std::string> string_array_;
};

然后我从这个结构中创建一个对象,如下所示:

StringContainer con(s1, s2);

其中s1和s2是本地定义的非常量std::字符串变量。我注意到初始值设定项列表中的string_array_赋值至少不会调用std::string的构造函数一次。(不适用于初始值设定项列表中的临时对象或插入到向量中的对象)。我读到,这可能适用于平凡可构造类,但平凡可构造性的要求之一是具有隐式默认构造函数/副本构造函数。但是std::string(std::basic_string)已经定义了两者。我在这里错过了什么?如果我想写一个字符串类来利用这种优化,我应该怎么做?

我的调试器让我确信构造函数是被调用的,但如果我不能使用调试器,我决定做一些小实验来获得证据。你也可以自己试试。

创建std::string的子类,用string2替换代码中的std::字符串,添加一些打印输出,并获得构造函数被调用的可视化证明:

class string2 : public string
{
public:
   string2(std::string s) : std::string(s)
   {
      std::cout << "string2 constructor" << std::endl;
   }
   string2(const string2& s) : std::string(s)
   {
      std::cout << "string2 copy constructor" << std::endl;
   }
};

可能是因为COW?

参见:

  • C++11内部std::字符串表示法(libstdc++)

引用那里的报价:

*  This approach has the enormous advantage that a string object
*  requires only one allocation.  All the ugliness is confined
*  within a single %pair of inline functions, which each compile to
*  a single @a add instruction: _Rep::_M_data(), and
*  string::_M_rep(); and the allocation function which gets a
*  block of raw bytes and with room enough and constructs a _Rep
*  object at the front.

另请参阅:

  • STL中的写时复制支持