gpt4 book ai didi

c++ - 通过 shared_ptr 共享类内存

转载 作者:行者123 更新时间:2023-11-28 06:21:19 25 4
gpt4 key购买 nike

我想在不同对象之间共享对象内存(例如,读取器/写入器访问相同的内存池)。它运行良好,但我在共享一个 shared_ptr 时遇到问题。

struct A {
A() {}

A(const A &other) {
i = other.i;
}

std::shared_ptr<int> i;
};

struct B : public A {
B(const A &other) : A(other) {}
};

我想让第二个例子工作,但它抛出了一个异常。因为变量 i 没有被初始化并且 shared_ptr 没有被复制(他是空的)。

{ // don´t throw
A a;
a.i = std::make_shared<int>(10);

B b(a);
*b.i = 11;

printf("%d\n", *a.i);
}
{ // throw
A a;
B b(a);

b.i = std::make_shared<int>(10);
printf("%d\n", *a.i);
}

只有 B 应该初始化变量 i。

下面是一个解决方案,但我真的需要其他包装类吗?

struct A {
A() : i(std::make_shared<std::vector<std::shared_ptr<int>>>()) {}

A(const A &other) {
i = other.i;
}

std::shared_ptr<std::vector<std::shared_ptr<int>>> i;
};

struct B : public A {
B(const A &other) : A(other) {}
};

int main(int argc, char *argv[]) {

{ // throw
A a;
B b(a);

b.i->emplace_back(std::make_shared<int>(10));
printf("%d\n", *a.i->at(0));
}
}

另一个例子就是使用原始指针,但我想问你,它如何与 shared_ptr 一起工作。

int 类型只是一个例子。它也可以是没有默认构造函数的重类。

最佳答案

你的第一个场景

你的代码抛出,因为:

  • 当你创建a时,a.i是一个空的shared_ptr
  • 然后您使用复制a 的构造函数创建b。所以 b.i 是一个空的 shared_ptr
  • 然后您将指向新创建对象的共享指针分配给 b.i。但这并没有改变 a.i 指针,它仍然是空的。
  • 最后您尝试取消引用 a.i。但是由于 a.i 是空的,即使用计数为 0 且没有有效指针,因此它是未定义的行为(可能会发生段错误)。

第一个场景的改进:

您可以通过定义 A 的默认构造函数轻松避免此陷阱:

    A() : i(std::make_shared<int>(0)) {}

ab 将指向同一个共享对象,并且您不会遇到段错误。

但是这种方法当然不会阻止有人将 b.i 重新分配给另一个共享指针。这就是 struct 的问题:您将 key 交给房子,由您来收拾残局。

改进的变体可以是一个完全封装的类,其中 i 将受到保护,函数或运算符可以访问 i。我选择了一种重载赋值形式 int 和转换为 int 的方式,以允许直观的使用,但这是一个品味问题:

class A {
public:
A() : i(std::make_shared<int>(0)) {}
A(const A &other) { i = other.i; }
operator int() { return *i; } // you can use A when you could use an int
A& operator= (int x) {
*i = x;
return *this;
}
// todo: copy assigment: take the pointer or take the value ?
protected:
std::shared_ptr<int> i;
};
struct B : public A {
B(const A &other) : A(other) {}
B& operator= (int x) {
*i = x;
return *this;
}
// todo: copy assigment: take the pointer or take the value ?
};

这个类的用法是:

{ // don´t throw
A a;
a = 10;
B b(a);
b = 11;
printf("%d\n", (int)a);
}
{ // don't throw either
A a;
B b(a);
a = 1;
cout << a <<endl;
cout << b << endl;
b = 10;
printf("%d\n", (int)a); // to make sure that only the int value is passed
}

你的第二个场景

在这种情况下,您已更改为使用指向共享指针 vector 的共享指针。

我看不出这段代码有什么问题,我也没有遇到过抛出:see online demo

你的其他想法

您当然可以使用原始指针,前提是它们已正确分配给 new。

int *pi = new int(1); 
shared_ptr<int> spi(pi);

但是注意:一旦你这样做了,shared_ptr 就拥有了所有权。这意味着 shared_ptr 负责对象的销毁。

如果你想在另一个 shared_ptr 中重用这个原始指针(或者更糟:如果它是从 shared_ptr 获得的),你的编译器不会提示,但你会在运行时得到未定义的行为,因为当第二个 shared_ptr 会尝试销毁已被第一个 shared_ptr 销毁的对象(如果从原始指针构造,shared_ptr 将不知道其他 shared_ptr 的存在)。

关于c++ - 通过 shared_ptr 共享类内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29269036/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com