0

I have a number of inheritance-related types that I want to use from standard container (std::reference_wrapper is a proper value type for such a container, AFAIU). However, I do not understand, how to initialize such a container when the values, the references to which are inserted in a map, are not global variables. E.g.:

#include <iostream>
#include <vector>
#include <functional>

using namespace std;

struct I
{
    virtual void print() = 0;
};

struct S1: public I
{
    void print() override
    {
        cout << "S1 " << i << endl;
    }
    int i{};
};

struct S2: public I
{
    void print() override
    {
        cout << "S2 " << f << endl;
    }
    float f{};
};

std::vector<reference_wrapper<I>> v;

void init()
{
    S1 x{};
    S2 y{};
    v.emplace_back(x);
    v.emplace_back(y);
}

int main()
{
    init();
    v[1].get().print();
    return 0;
}

This compiles, but I get some memory corruption at run-time. What is a proper way of initializing container of std::reference_wrappers?

1
  • 3
    If you need v to own the instances you store within, you need it to be an std::vector<std::unique_ptr<I>> and use dynamic allocation through std::make_unique<I>(). Commented Sep 9, 2019 at 13:06

2 Answers 2

2

You can't have a reference to a function local object. Once the function exits those local objects are destroyed and you are left with dangling references in the vector. What you can do to fix this is to switch to using a std::unique_ptr<I> and std::make_unique which dynamically allocates the objects you want to store in the vector. The std::unique_ptr will manage the memory and once the vector is destroyed it will destroy the std::unique_ptr's that are in the vector and they will in turn delete the memory that was acquired to hold the objects. That would give you

#include <iostream>
#include <vector>
#include <functional>
#include <memory>

using namespace std;

struct I
{
    virtual void print() = 0;
};

struct S1: public I
{
    void print() override
    {
        cout << "S1 " << i << endl;
    }
    int i{};
};

struct S2: public I
{
    void print() override
    {
        cout << "S2 " << f << endl;
    }
    float f{};
};

std::vector<unique_ptr<I>> v;

void init()
{
    v.emplace_back(std::make_unique<S1>()); // creates a defaulted S1 in the unique_ptr
    v.emplace_back(std::make_unique<S2>()); // creates a defaulted S2 in the unique_ptr
}

int main()
{
    init();
    v[1]->print(); // or (*v[1]).print()
    return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

0

The problem you are facing is that your objects S1 x and S2 y are destroyed at the end of your init function. So, at the end of init(), your vector v contains references to nothing. Therefore, when trying to call print(), you get a segmentation fault.

In a similar way, consider this code:

int& get_i()
{
    int i = 1;
    return i;
}

int main()
{
    std::cout << get_i() << std::endl; // segmentation fault
    return 0;
}

This as well produces a segmentation fault as get_i() returns a reference to a local variable (which gets destroyed at the end if get_i()).

You could user std::unique_ptr instead as mentioned in one of the comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.