SlySherZ
SlySherZ

Reputation: 1661

Late non-copyable member initialization

I'm trying to initialize a object's member that cannot be assigned nor copied. I need some other tasks to be performed first and the initialization depends on it, so I have to delay it.

#include <boost/process.hpp>

class A{
    std::unique_ptr<boost::process::child> child_;
    std::unique_ptr<boost::process::pistream> is;

    A(std::string exec, boost::process::context process_context){
        // Stuff that needs to be done first
        // ...

        child_ = std::make_unique<boost::process::child>(start_child(exec, process_context));
        is = std::make_unique<boost::process::pistream>(child_->get_stdout()); // <- error

    }

    boost::process::child start_child(std::string exec, boost::process::context process_context);
};

The error I get from this is:

error C2280: 'std::basic_ios>::basic_ios(const std::basic_ios> &)' : attempting to reference a deleted function

If I understand this correctly, somewhere in that line a copy is happening, which isn't allowed. The unique pointers are not required. I just use them to avoid another error (no default initialization) but I would be happy to accept suggestions both with or without them.

Upvotes: 2

Views: 256

Answers (2)

Tristan Brindle
Tristan Brindle

Reputation: 16824

The problem is that std::unique_ptr wants ownership of the pistream, so it tries to take a copy, which as you have discovered isn't allowed. If you think about it, this makes sense: you certainly don't want std::unique_ptr<b::p::pistream> deleting _child's stream in its destructor.

The easiest solution would be to just use a regular, non-owning pointer instead, say:

class A{
    std::unique_ptr<boost::process::child> child_;
    boost::process::pistream* is = nullptr;

    A(std::string exec, boost::process::context process_context){
        // ...
        child_ = std::make_unique<boost::process::child>(start_child(exec, process_context));

        is = &child_->get_stdout();
    }
};

Of course, you'd want to check that is is not nullptr before actually using it, but the same is true for a unique_ptr.

Upvotes: 3

sehe
sehe

Reputation: 393114

You can use boost::optional<> for lazy initialization like this.

Live On Coliru

#include <memory>
#include <boost/optional.hpp>

struct pistream { };
struct child    {
    pistream& get_stdout() { return is; }
    pistream is;
};
struct context  { };

class A {
    std::unique_ptr<child> child_;
    boost::optional<pistream&> is;

    A(std::string, context) {
        // Stuff that needs to be done first
        // ...

        child_ = std::make_unique<child>();
        is     = child_->get_stdout();
    }
};

Upvotes: 3

Related Questions