Smart pointers get confused in initializer list

I am trying to run a simple piece of code with shared pointers.

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

      

Compilation was successful but "The program stops working" when I try to run it. I went through the code and it failed when execution leaves main

(this is the function that contains this code).

Interestingly, when I explicitly add a constructor around the expression, it works:

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

      

I have three questions:

  • What happens when I pass a local variable shared_ptr

    ( expression

    in this case) to the initializer list? I thought the copy constructor would be called, creating a new one shared_ptr

    to initialize collection I.
  • Is it possible that this one shared_ptr

    in the collection that is pointed to expression

    in the function scope will not contain a valid pointer just because the constructor expression

    hasn't finished yet?
  • Does it matter that the program stops working { __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }

    somewhere in <atomicity.h>

    , or is it just a random location?
+3


source to share


1 answer


A variable is not initialized when used inside an initializer list. See what happens:

#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();
}

      

Output:



expression: 536937312? 2282820

An attempt to access failed expression->rules[1][0]->name

;

+1


source







All Articles