C++:创建共享对象而不是指向对象的共享指针
boost::shared_ptr 真的很困扰我。当然,我理解这样的东西的实用性,但我希望我可以使用 shared_ptr
作为 A*
。考虑以下代码
class A
{
public:
A() {}
A(int x) {mX = x;}
virtual void setX(int x) {mX = x;}
virtual int getX() const {return mX;}
private:
int mX;
};
class HelpfulContainer
{
public:
//Don't worry, I'll manager the memory from here.
void eventHorizon(A*& a)
{
cout << "It's too late to save it now!" << endl;
delete a;
a = NULL;
}
};
int main()
{
HelpfulContainer helpfulContainer;
A* a1 = new A(1);
A* a2 = new A(*a1);
cout << "*a1 = " << *a1 << endl;
cout << "*a2 = " << *a2 << endl;
a2->setX(2);
cout << "*a1 = " << *a1 << endl;
cout << "*a2 = " << *a2 << endl;
cout << "Demonstrated here a2 is not connected to a1." << endl;
//hey, I wonder what this event horizon function is.
helpfulContainer.eventHorizon(a1);
cout << "*a1 = " << *a1 << endl;//Bad things happen when running this line.
}
无论创建 HelpfulContainer 的人都没有考虑其他人想要保留指向 A 对象的指针。我们不能给 HelpfulClass boost::shared_ptr 对象。但我们可以做的一件事是使用 pimlp 习惯用法创建一个 SharedA,它本身就是一个 A:
class SharedA : public A
{
public:
SharedA(A* a) : mImpl(a){}
virtual void setX(int x) {mImpl->setX(x);}
virtual int getX() const {return mImpl->getX();}
private:
boost::shared_ptr<A> mImpl;
};
然后 main 函数可以如下所示:
int main()
{
HelpfulContainer helpfulContainer;
A* sa1 = new SharedA(new A(1));
A* sa2 = new SharedA(sa1);
cout << "*sa1 = " << *sa1 << endl;
cout << "*sa2 = " << *sa2 << endl;
sa2->setX(2);
cout << "*sa1 = " << *sa1 << endl;
cout << "*sa2 = " << *sa2 << endl;
cout << "this demonstrates that sa2 is a shared version of sa1" << endl;
helpfulContainer.eventHorizon(sa1);
sa2->setX(3);
//cout << "*sa1 = " << *sa1 << endl;//Bad things would happen here
cout << "*sa2 = " << *sa2 << endl;
//but this line indicates that the originally created A is still safe and intact.
//only when we call sa2 goes out of scope will the A be deleted.
}
所以,我的问题是: 是上面的模式吗一个好的模式,或者还有什么我还没有考虑的。我当前的项目继承了一个像上面这样的 HelpfulContainer
类,它删除了我需要的指针,但我仍然需要 HelpfulContainer 中存在的数据结构。
更新:这个问题是一个后续问题。
boost::shared_ptr really bothers me. Certainly, I understand the utility of such a thing, but I wish that I could use the shared_ptr<A>
as an A*
. Consider the following code
class A
{
public:
A() {}
A(int x) {mX = x;}
virtual void setX(int x) {mX = x;}
virtual int getX() const {return mX;}
private:
int mX;
};
class HelpfulContainer
{
public:
//Don't worry, I'll manager the memory from here.
void eventHorizon(A*& a)
{
cout << "It's too late to save it now!" << endl;
delete a;
a = NULL;
}
};
int main()
{
HelpfulContainer helpfulContainer;
A* a1 = new A(1);
A* a2 = new A(*a1);
cout << "*a1 = " << *a1 << endl;
cout << "*a2 = " << *a2 << endl;
a2->setX(2);
cout << "*a1 = " << *a1 << endl;
cout << "*a2 = " << *a2 << endl;
cout << "Demonstrated here a2 is not connected to a1." << endl;
//hey, I wonder what this event horizon function is.
helpfulContainer.eventHorizon(a1);
cout << "*a1 = " << *a1 << endl;//Bad things happen when running this line.
}
Whoever created the HelpfulContainer wasn't thinking about others wanting to retain pointers to A objects. We can't give HelpfulClass boost::shared_ptr objects. But one thing we could do is use the pimlp idiom to create a SharedA which itself is an A:
class SharedA : public A
{
public:
SharedA(A* a) : mImpl(a){}
virtual void setX(int x) {mImpl->setX(x);}
virtual int getX() const {return mImpl->getX();}
private:
boost::shared_ptr<A> mImpl;
};
And then the main function can look something like this:
int main()
{
HelpfulContainer helpfulContainer;
A* sa1 = new SharedA(new A(1));
A* sa2 = new SharedA(sa1);
cout << "*sa1 = " << *sa1 << endl;
cout << "*sa2 = " << *sa2 << endl;
sa2->setX(2);
cout << "*sa1 = " << *sa1 << endl;
cout << "*sa2 = " << *sa2 << endl;
cout << "this demonstrates that sa2 is a shared version of sa1" << endl;
helpfulContainer.eventHorizon(sa1);
sa2->setX(3);
//cout << "*sa1 = " << *sa1 << endl;//Bad things would happen here
cout << "*sa2 = " << *sa2 << endl;
//but this line indicates that the originally created A is still safe and intact.
//only when we call sa2 goes out of scope will the A be deleted.
}
So, my question is this: Is the above pattern a good pattern, or is there something I'm not considering yet. My current project inherited a HelpfulContainer
class like above that's deleting the pointers that I need, but I still need the data structure present in the HelpfulContainer.
Update: This question is a follow-on question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
shared_ptr
的全部要点是它(及其副本)拥有它指向的对象。如果您想为管理其生命周期的容器提供一个A
,那么您根本不应该使用shared_ptr
,因为它不能满足您的需求;HelpfulContainer
只知道如何成为动态创建的对象的唯一所有者,因此您需要为其提供一个指向不属于其他任何对象的对象的指针。我认为对于一个对象来说,关心自己的生命周期通常是糟糕的设计(也有例外)。如果一个对象可以完成一项工作,并且由其他东西管理其创建和销毁,选择尽可能简单的生命周期策略(例如本地/自动变量),那么通常会更有用。
如果您绝对必须在两个不合作的事物之间共享所有权(例如
shared_ptr
和HelpfulContainer
),那么您将必须使用某种代理技术。但在这种情况下,看起来
HelpfulContainer
对您的情况没有多大帮助。The whole point of
shared_ptr
is that it (and its copies) own the object that it points to. If you want to give anA
to a container that manages its lifetime then you shouldn't be using ashared_ptr
at all as it doesn't meet your needs;HelpfulContainer
only knows how to be the sole owner of a dynamically created object so you need to give it a pointer to an object that isn't owned by anything else.I think that it is usually poor design for an object to care about its own lifetime (there are exceptions). It is usually more useful if an object can do a job and something else manages its creation and descruction, choosing the simplest lifetime strategy possible (e.g. local/automatic variable).
If you absolutely have to share ownership between two things that don't co-operate (such as
shared_ptr
andHelpfulContainer
) then you will have to use some sort of proxy technique.In this case, though, it just looks like
HelpfulContainer
just isn't that helpful for your situation.我不确定这对你有什么作用。
如果
helpfulContainer.eventHorizon()
always 删除其参数,那么为什么不直接传递(原始)A 类的新副本:或者,如果
helpfulContainer.eventHorizon ()
仅有时删除其参数,然后进行调用,因为在选择不删除的情况下,两者都会泄漏 SharedA 和原始 A (sa1)删除。
I'm not sure what this does for you.
If
helpfulContainer.eventHorizon()
always deletes its parameter, then why not just pass a new copy of (the original) A class:Or, if
helpfulContainer.eventHorizon()
only sometimes deletes its parameter, then making the call aswill leak both the SharedA and the original A (sa1) on those occasions when it chooses not to delete.
因此,您正在创建一个可以删除的替身 (SharedA)。尽管这有点尴尬,但我想有必要使用您的旧版 API。要稍微改进这一点:允许从shared_ptr构造SharedA,但反之则不然——然后仅在绝对必须时使用SharedP:
So you are creating a Stand-In (SharedA) for which deletion is okay. Even though this is kinda awkward, I guess it's necessary to work with your legacy API. To slightly improve this: Allow construction of SharedA from a shared_ptr, but not the other way around - and then only use the SharedP when you absolutely must:
到底层指针类型的隐式转换与
shared_ptr
的预期用途不一致,因为您可以非常轻松地将shared_ptr
传递给函数等,而无需意识到这一点。在我看来,
HelpfulContainer
毫无用处,应该修复或放弃。如果这是不可能的,那么最好的方法可能就是复制您想要传入的
A
并将副本传递到容器。Implicit conversions to the underlying pointer type are inconsistent with the intended use of
shared_ptr
in that you can extremely easily pass theshared_ptr
to a function etc without realizing it.It sounds to me like
HelpfulContainer
is anything BUT helpful and should be fixed or ditched.If that's not possible then probably the best way is to just copy the
A
you want to pass in and pass the copy to the container.