【问题标题】:How to move stack object into std::shared_pointer without instantiation如何在不实例化的情况下将堆栈对象移动到 std::shared_ptr
【发布时间】:2020-05-02 20:30:31
【问题描述】:

问题

你好。我有一个有点奇怪的问题。假设您有一个不可复制的堆栈对象,它是从外部库中获得的。如何在不实际实例化类的情况下将内容移动到由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 将新创建的对象的内容从指定的对象中移出?

【问题讨论】:

    标签: c++ scope shared-ptr


    【解决方案1】:

    这是可以做到的。不需要任何技巧。只需移动对象:

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

    关于你的评论:

    没有实际实例化类?

    (以防构造函数进行一些更改)。

    这完全不合理。如果构造函数没有做它应该做的事情,那么这个类就是错误的。

    更清楚地说:您要解决的问题是:您有一个由外部库中的值提供的对象。该对象是只能移动的。您想将此对象放入共享指针的容器中。这就是问题。在解决这个问题时,您认为您不能使用移动构造函数,但事实并非如此。解决方案是使用我展示的移动构造函数。

    【讨论】:

    • 你实例化了一个新对象。您只需从obj 移动构建它。这没有回答问题
    • 您显然是在实例化my_class 的一个实例。只是使用的构造函数是move构造函数。
    • @sparik 好的,我同意这正是 OP 想要的。但是我告诉他/她并不是真的想要那个,这是一个没有意义的要求,解决方案就是我提出的。 OP 误以为他/她不能实例化一个新对象并移入其中
    • @arsdever 我实例化了一个新对象并通过从旧对象移动来初始化它。
    • 我不明白 - 谁否决了这个答案,因为这回答了我的问题。谢谢@bolov。
    【解决方案2】:

    以防万一您出于某种原因需要它,这里有一个适用于既不能移动也不能复制的类的技巧。这有点可怕;我不会在实践中推荐它。

    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 鲜为人知的特性,它可以管理一个对象但公开指向另一个对象的指针(通常是第一个对象的子对象)。

    【讨论】:

    • 这不起作用 new(&amp;data) my_class{getMyClassObject()} 要求 my_class 可复制或可移动
    • @bolov 不比my_class obj = getMyClassObject(); 多。两者都依赖于 C++17 中的保证复制省略。看演示 - 我明确删除了复制和移动构造函数,但它编译并运行(-std=c++17 但不是-std=c++14
    • 哦,是的。您应该补充一点,它需要 C++17
    • @bolov 同样,my_class obj = getMyClassObject(); 也是如此。问题陈述在 C++17 之前没有意义。
    • 在 OP 示例中,对象是可移动的。
    猜你喜欢
    • 2015-11-08
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 2018-03-29
    • 2020-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多