如何在不实例化的情况下将堆栈对象移动到 std::shared_pointer
How to move stack object into std::shared_pointer without instantiation
问题
你好。我有一个有点奇怪的问题。假设您有一个不可复制的堆栈对象,您是从外部库中获得的。如何在不实际实例化 class 的情况下将内容移动到 std::make_shared
分配的堆对象中?
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)
}
一个“解决方案”可能是创建对象的实例然后替换它,如下所示
std::shared_ptr<my_class> ptr = std::make_shared<my_class>(arguments_needed);
*ptr.get() = std::move(obj);
shared_pointers_container.insert(ptr);
但这不是一个好的解决方案(以防构造函数进行一些更改)。
也许有一种方法可以告诉 std::make_shared
从指定对象中移动新创建对象的内容?
可以做到。不需要技巧。只需移动对象:
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)););
关于您的评论:
without actually instantiating the class?
(in case the constructor does some changes).
这完全没有道理。如果构造函数没有做它应该做的事情,那么 class 就是错误的。
更清楚地说:您要解决的问题是:您有一个从外部库中按值给出的对象。该对象是只能移动的。你想把这个对象放到一个共享指针的容器中。这就是问题。在解决这个问题时,您认为您不能使用移动构造函数,但事实并非如此。解决方案是使用我展示的移动构造函数。
以防万一您出于某种原因需要它,这里有一个适用于既不可移动也不可复制的 class 的技巧。这有点可怕;我不会在实践中推荐它。
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.
这依赖于std::shared_ptr
鲜为人知的特性,它可以管理一个对象,但暴露一个指向另一个对象(通常是第一个对象的子对象)的指针。
问题
你好。我有一个有点奇怪的问题。假设您有一个不可复制的堆栈对象,您是从外部库中获得的。如何在不实际实例化 class 的情况下将内容移动到 std::make_shared
分配的堆对象中?
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)
}
一个“解决方案”可能是创建对象的实例然后替换它,如下所示
std::shared_ptr<my_class> ptr = std::make_shared<my_class>(arguments_needed);
*ptr.get() = std::move(obj);
shared_pointers_container.insert(ptr);
但这不是一个好的解决方案(以防构造函数进行一些更改)。
也许有一种方法可以告诉 std::make_shared
从指定对象中移动新创建对象的内容?
可以做到。不需要技巧。只需移动对象:
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)););
关于您的评论:
without actually instantiating the class?
(in case the constructor does some changes).
这完全没有道理。如果构造函数没有做它应该做的事情,那么 class 就是错误的。
更清楚地说:您要解决的问题是:您有一个从外部库中按值给出的对象。该对象是只能移动的。你想把这个对象放到一个共享指针的容器中。这就是问题。在解决这个问题时,您认为您不能使用移动构造函数,但事实并非如此。解决方案是使用我展示的移动构造函数。
以防万一您出于某种原因需要它,这里有一个适用于既不可移动也不可复制的 class 的技巧。这有点可怕;我不会在实践中推荐它。
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.
这依赖于std::shared_ptr
鲜为人知的特性,它可以管理一个对象,但暴露一个指向另一个对象(通常是第一个对象的子对象)的指针。