【问题标题】:Constructor Initializer List in C++C++ 中的构造函数初始化列表
【发布时间】:2017-03-07 00:44:51
【问题描述】:

请先看以下代码:

class StrBlob
{
    public:
        StrBlob();
        // ....
    private:
        std::shared_ptr<std::vector<std::string> > data;
}
//initializer empty into data ;

StrBlob::StrBlob()
// : data(std::make_shared<std::vector<std::string> >())      // compile success
{
 //  data(std::make_shared<std::vector<std::string> >());     // compile error
}
int main()
{
    // this statement can compile
    std::shared_ptr<std::vector<std::string> >data(std::make_shared<std::vector<std::string> >());
    return 0;
}

我想知道为什么上面的语句编译会出现错误? ?

error: no match for call to ‘(std::shared_ptr<std::vector<std::__cxx11::basic_string<char> > >)
   (std::shared_ptr<std::vector<std::__cxx11::basic_string<char> > >)’
   data(std::make_shared<std::vector<std::string> >());

C++Primer 5th (Chapter 7.5)中引用的相应知识如下:

我们可以经常(但并非总是)忽略成员是初始化还是分配之间的区别。必须初始化 const 或引用的成员。类似地,未定义默认构造函数的类类型的成员也必须初始化

首先我将分享我的想法。“数据”成员在构造函数开始执行之前默认初始化。正确的?那么,构造函数中的“数据”成员将复制从函数 make_shared.right 创建的对象?

【问题讨论】:

  • 因为你不能在构造函数的主体内构造/初始化对象。它只允许在初始化列表中。不过,您可以 assign 到主体内已构建的对象。
  • “虽然你可以赋值给body内部已经构建好的对象”但是你不应该在c++代码中养成习惯。

标签: c++ c++11 initializer


【解决方案1】:

第一个编译成功,因为您在成员初始化列表中初始化了 data,这样的语法在这里完全有效。更多信息请查看this

第二个等于data(...)。它不是 data 对象的构造,编译器将其视为为已创建的 data 成员调用 operator() 的尝试(并在错误消息中说明)。

最后在 main 函数中,您只需使用 shared_ptr 复制构造函数从返回的 shared_ptr 创建 data make_shared

【讨论】:

  • 你说得对。第二个数据(..)是调用复制构造函数?但是在调用 data(..) 之前已经创建了数据对象。如果是这样的话。这意味着调用复制构造函数两次。编译时会出现错误。我说对了吗?
  • 不,第二个不是复制构造函数调用。这是对operator() 的调用,它不会为您的班级重载。这就是它无法编译的原因。
  • 我想了一会儿,然后你才不同意我的想法。我尝试重载 operator() 成员。它工作。对应给定编译器的错误,我想我知道。向您致以最良好的祝愿!最后我想问一下是不是也可能是因为调用了两次拷贝构造函数而报错了,只是编译器没有报错??
  • @AndyCong 我不明白你怎么可以调用复制构造函数两次。只需在成员初始化器列表中调用一次...
  • 也许这些是我观点的错误。我想太多了。因为 data(..) 的行为看起来像复制构造函数,我认为问题可以简化如下代码: std::vector vec1,vec2; vec1(vec2);然后第二个陈述就是我们谈论的问题。看起来是复制构造函数的行为吗?你认为 ?我需要你的帮助。
【解决方案2】:

如果出于多种原因想稍后初始化数据对象,可以在 StrBlob 初始化列表和 StrBlob 构造函数的主体中使用 std::shared_ptr 默认构造函数 - reset 功能:

StrBlob::StrBlob()
 : data()
{
   data.reset(new std::vector<std::string>());
}

【讨论】:

  • 我想我们应该避免这样的结构,因为这段代码不是最优的。例如,参见 Meyers 的书籍。
  • @EdgarRokyan 这是一个简单的例子。在实践中,你不能总是初始化初始化列表中的对象,因为有时你想计算一些输入参数。关于效率,我只是调用默认构造函数和重置函数。我创建了一次矢量对象。我不质疑你的回答。事实上,我同意它。我的帖子的目的是展示另一种解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-23
  • 1970-01-01
  • 2013-10-03
  • 1970-01-01
  • 2011-01-06
  • 2014-07-14
  • 1970-01-01
相关资源
最近更新 更多