【问题标题】:How to "reassign" a shared_ptr<base> to a new derived object如何将 shared_ptr<base>“重新分配”给新的派生对象
【发布时间】:2021-08-15 08:23:57
【问题描述】:

我正在使用 C++ 编写解释性语言。现在的问题是我想实现重新分配之类的功能:

VAR a = [1,"2",[3,4]]
VAR a[0] = 100

在我的语言中,List 是shared_ptr&lt;Data&gt;vector,这样您就可以在一个列表中存储不同类型的数据。如果有人要更改元素,我可以得到shared_ptr&lt;Data&gt; elem,以及即将分配的shared_ptr&lt;Data&gt; value

类似:

shared_ptr<Data> elem = visit(elem_node)
shared_ptr<Data> value = visit(value_node)
*elem = *value;

抱歉,我忘了说 visit() 返回的是一个值,而不是一个引用,这就是为什么我没有让 elem=value;

事实证明,唯一改变的是来自Data 类的数据成员。

但我想要的是让shared_ptr“重新指向”一个新对象。有可能吗?

我试过dynamic_pointer_cast,如果原始元素和新值是同一类型,一切都很好。但正如我所指出的,我允许在一个列表中包含不同类型的元素,所以这只能是我的最后一根稻草。

我已经根据 Remy Lebeau 的回答编写了一个演示代码(谢谢):

#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;

struct Data
{
    virtual ~Data() = default;
    virtual void print() = 0;
};

struct Integer : Data
{
    int value;
    Integer(int val) : value(val) {}
    void print() override { cout << "integer(" << value << ")" << endl; }
};

struct String : Data
{
    string value;
    String(string val) : value(val) {}
    void print() override { cout << "string(\"" << value << "\")" << endl; }
};

struct RuntimeResult
{
    RuntimeResult success(const shared_ptr<Data> &value)
    {
        this->value = value;
        return (*this);
    }

    shared_ptr<Data> registry(const RuntimeResult &res)
    {
        // this is for handling error
        // but this simplify version simply return value;
        return res.value;
    }

    shared_ptr<Data> value;
};

int main()
{
    // simulate a List variable
    vector<shared_ptr<Data>> list;
    list.push_back(make_shared<Integer>(123456));
    list.push_back(make_shared<String>("hello"));

    RuntimeResult res;

    // inside registry, it should be something like visit_IndexNode(elem_node)
    // to interprete a node on AST Tree
    // but the return is simply like what have shown below
    shared_ptr<Data> elem = res.registry(RuntimeResult().success(list.at(0)));
    // Using Visual Studio 2019's debugging mode
    // we can see that elem's ptr == list[0]'s ptr
    // in other word, they are pointing to the same thing(123456)

    shared_ptr<Data> value = res.registry(RuntimeResult().success(make_shared<String>("test")));

    elem = value;
    elem->print(); // "test"

    list[0]->print(); // still 123456

    return 0;
}

这正是我的问题

【问题讨论】:

    标签: c++ vector polymorphism shared-ptr


    【解决方案1】:

    但我想要的是让shared_ptr“重新指向”一个新对象。有可能吗?

    是的。只需将一个 shared_ptr&lt;Data&gt; 分配给另一个,无需强制转换:

    shared_ptr<Data> &elem = ...;
    shared_ptr<Data> value = ...;
    elem = value;
    

    Online Demo

    【讨论】:

    • 您可以这样做的原因是通过返回参考。我已经尝试过了,但它一直在递增使用计数时崩溃,出现 0xCCCCCCCC 内存访问错误,所以我的返回值只是一个没有 & 的 shared_ptr
    • 我看看能不能做到。但是如果没问题,你可以去看看我的回购github.com/Morphlng/Basic。您要查看的部分位于 src/Interpreter 下。问题出现在函数 visit_MutateNode 中,假设返回 shared_ptr elem 的代码就在它的下面,visit_IndexNode。
    • @Morphlng 您的示例并没有满足您的要求,因为它根本没有修改列表的内容。我的例子确实如此。此外,您的示例也没有演示内存访问错误。请使用minimal reproducible example 更新您的问题,不要要求人们从外部站点下载代码。但我可以告诉你,你指出的代码效率很低,需要认真重写。您正在制作大量不必要的对象副本,并且您的类型化处理非常难看。有更好的设计选择(多态性​​等)
    • 是的,这是我第一次使用这些多态性的东西,我会在实现大部分功能后尝试改进这些代码。
    【解决方案2】:

    正如 Remy 指出的那样,我的起源问题是由于设计不当造成的。但是,我已经设法通过使用shared_ptr&lt;unique_ptr&lt;Base&gt;&gt; 来解决它。

    想法是以某种方式将shared_ptr 的所有引用更改为“重新指向”新的派生对象。按照这个想法,我找到了一个问答Replace all references to a object in a shared_ptr

    通过添加第二层间接,我可以执行以下操作:

    class Data;
    
    class Integer:public Data;
    
    class String:public Data;
    
    shared_ptr<unique_ptr<Data>> origin_value = make_shared<unique_ptr<Data>>(make_unique<Integer>(123));
    
    auto copy = origin_value;
    
    shared_ptr<unique_ptr<Data>> new_value = make_shared<unique_ptr<Data>>(make_unique<String>("hello"));
    
    (*copy).reset((*new_value).release());
    

    这会将origin_valuecopy 都更改为new_value

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-27
      • 1970-01-01
      • 2012-01-13
      • 1970-01-01
      相关资源
      最近更新 更多