【问题标题】:Smart pointers messed with initializer list智能指针与初始化列表混淆
【发布时间】:2014-08-30 16:34:51
【问题描述】:

我正在尝试使用共享指针运行一段简单的代码。

//in the class definition
Rule(std::string name, 
     std::vector<std::vector<std::shared_ptr<RuleMember>>> rules);
...

//in function 'main'
shared_ptr<Rule> expression(new Rule("expression", {
    { identifier },
    { expression, add, identifier }
}));

编译成功,但是当我尝试运行它时“程序停止工作”。我单步执行了代码,当执行离开main(这是包含此代码的函数)时它失败了。

有趣的是,当我在表达式周围显式添加构造函数时,它可以工作:

shared_ptr<Rule> expression(new Rule("expression", {
    { identifier },
    { shared_ptr<Rule> (expression), add, identifier }
}));

我有三个问题:

  1. 当我将本地shared_ptr 变量(在本例中为expression)传递给初始化列表时会发生什么?我以为会调用一个复制构造函数,为我初始化的集合创建一个新的shared_ptr
  2. 函数作用域中expression 指向的集合中的这个shared_ptr 是否可能因为expression 的构造函数尚未完成而不包含有效指针?
  3. 程序在{ __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); } 某处在&lt;atomicity.h&gt; 停止工作的事实与此有关,还是只是一个随机的地方?

【问题讨论】:

  • 关于 (1),由于您正在构建您想要复制的对象,我不知道这将如何发生。您对 (2) 是 (1) 失败的直接结果的推测(至少在我阅读您的代码时)似乎是合理的。仅供参考,对于第一个示例,clang 将显示警告(“变量expression 在其自己的初始化中使用时未初始化”)。我很难形容它比这更好。
  • @WhozCraig,那么这意味着我必须在创建智能指针后初始化 Rule 对象。我想我会节省一些台词。谢谢。
  • @firda,我相信我不会创建两个 distict shared_ptrs:en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr (9)
  • 小心。如果我在这里理解您的使用模式(相当大的“如果”),您可能会创建一个循环自引用共享指针(它通过自己的规则向量引用自己)。您可能想考虑弱指针如何更适合这里的某个地方(注意:除了自引用共享指针的潜在问题之外,我还没有真正考虑过它)。祝你好运。
  • 谢谢,我会考虑的。也许你可以把你的 cmets 写成一个 aswer..

标签: c++ c++11 shared-ptr copy-constructor initializer-list


【解决方案1】:

变量在初始化列表中使用时未初始化。看看会发生什么:

#include <memory>
#include <string>
#include <vector>
#include <iostream>
using std::shared_ptr;
using std::string;
using std::vector;

struct Rule {
    string name;
    vector<vector<shared_ptr<Rule>>> rules;
    Rule(string name,
      vector<vector<shared_ptr<Rule>>> rules)
    : name(name), rules(rules) {}
};

using std::cout;
using std::endl;

int main() {
    shared_ptr<Rule> identifier, add;
    shared_ptr<Rule> expression(new Rule("expression", {
        { identifier },
        { expression, add, identifier }
    }));

    cout << expression->name << ": "
        << (uintptr_t)expression.get() << " ? "
        << (uintptr_t)expression->rules[1][0].get();
}

输出:

表达式:536937312 ? 2282820

当我尝试访问 expression-&gt;rules[1][0]-&gt;name 时它崩溃了;

【讨论】:

  • 很惊讶我没有收到任何警告 (g++ -Wall -pedantic)
  • clang 更好:warning: variable 'expression' is uninitialized when used within its own initialization [-Wuninitialized] - { expression, add, identifier }
  • 这是否可以报告为错误(或缺少警告)?
  • @user35443: 也许,使用 Cygwin GCC 4.8.3 32bit
猜你喜欢
  • 2020-10-01
  • 2012-10-27
  • 2015-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-18
相关资源
最近更新 更多