1

Question

Hi there. I have a bit weird question. Suppose you have a non-copiable stack object, which you have gotten from an external library. How is it possible to move the content into a heap object allocated by std::make_shared without actually instantiating the class?

class my_class {
private:
  my_class(my_class const&) = delete;

public:
  my_class(some_arg_t some_args);
  my_class(my_class&& move);
}

// later on

std::unordered_set<std::shared_ptr<my_class>> shared_pointers_container;

int foo() {
  my_class obj = getMyClassObject();
  shared_pointers_container.insert(// moving obj into heap memory and get the shared pointer to it)
}

One "solution" could be to create an instance of the object and then replace it, like shown below

  std::shared_ptr<my_class> ptr = std::make_shared<my_class>(arguments_needed);
  *ptr.get() = std::move(obj);
  shared_pointers_container.insert(ptr);

but it's not a good solution (in case the constructor does some changes).

Maybe a way to tell std::make_shared to move the content of newly created object from the specified object?

2 Answers 2

2

It can be done. No tricks needed. Just move the object:

shared_pointers_container.insert(std::make_shared<my_class>(getMyClassObject()));

// or if you need to start from `obj`:

my_class obj = getMyClassObject();
// work with obj
shared_pointers_container.insert(std::make_shared<my_class>(std::move(obj)););

On your remarks:

without actually instantiating the class?

(in case the constructor does some changes).

This is completely unreasonable. If the constructor doesn't do what it is supposed to do then the class is buggy.

To be more clear: the problem you are trying to solve is this: You have an object given by value from an external library. This object is move-only. You want to put this object into a container of shared pointers. This is the problem. In solving this problem you think you cannot use the move constructor but that is definitely not the case. The solution is to use the move constructor how I showed.

Sign up to request clarification or add additional context in comments.

14 Comments

You instantiate a new object. You just move construct it from obj. This does not answer the question
You are obviously instantiating an instance of my_class. It's just that the constructor used is the move constructor.
@sparik ok, I agree that's strictly what the OP wants. However I am telling that he/she doesn't really want that, it's a requirement that makes not sense and the solution is what I present. The OP is missguided in thinking he/she cannot instantiate a new object and move into it
@arsdever I instantiate a new object and initialize it by moving from the old one.
I don't understand - who downvoted this answer, cause this answers my question. Thanks @bolov.
|
2

Just in case you need it for some reason, here's a trick that works for a class that's neither movable nor copyable. It's kind of horrifying; I wouldn't recommend it in practice.

class Wrapper {
    std::aligned_storage_t<sizeof(my_class), alignof(my_class)> data;
public:
    Wrapper() { new(&data) my_class{getMyClassObject()}; }
    ~Wrapper() { get()->~my_class(); }
    my_class* get() { return reinterpret_cast<my_class*>(&data); }
};

int main()
{
    auto wp = std::make_shared<Wrapper>();
    std::shared_ptr<my_class> p(wp, wp->get());
}

Demo.

This relies on the little-known feature of std::shared_ptr, where it can manage one object but expose a pointer to another (usually the sub-object of the first object).

7 Comments

this doesn't work new(&data) my_class{getMyClassObject()} requires my_class to be copyable or movable
@bolov Not any more than my_class obj = getMyClassObject(); does. Both rely on guaranteed copy elision in C++17. Look at the demo - I explicitly deleted both copy and move constructors, and yet it compiles and runs (with -std=c++17 but not with -std=c++14)
oh yeah. You should add that it requires C++17
@bolov Again, so does my_class obj = getMyClassObject(); The problem statement doesn't make sense pre-C++17.
in the OP example the object is movable.
|

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.