我想在不同对象之间共享对象内存(例如,Reader / Writer访问相同的内存池)。它工作状态良好,但我遇到共享一个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应该是init变量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类型只是一个例子。它也可能是一个没有默认构造函数的繁重类。
答案 0 :(得分:1)
您的代码会抛出,因为:
a
时,a.i
为空shared_ptr
b
的构造函数创建a
。因此,b.i
为空shared_ptr
b.i
。但这并没有改变a.i
指针,它仍然是空的。 a.i
。但由于a.i为空,即使用次数为0且没有有效指针,因此它的未定义行为(可能会发生段错误)。 通过定义A:
的默认构造函数,您可以轻松避免这个陷阱 A() : i(std::make_shared<int>(0)) {}
然后 a
和b
将指向同一个共享对象,您将不会遇到段错误。
但是这种方法当然不会阻止某人将b.i
重新分配给另一个共享指针。那是struct
的问题:你把钥匙交给房子,由你来清理这个烂摊子。
改进的变体可以是完全封装的类,其中我将受到保护,函数或操作符可以访问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
}
在这种情况下,您已更改为使用共享指针向量的共享指针。
我发现此代码没有任何问题,而且我没有投掷过:see online demo
您可以使用原始指针,前提是它们已经正确分配了新的指针。
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的存在)。