为了获得引用计数,我是否必须使用shared_ptr来扰乱我的API?
我最近遇到了以下内存错误,在这里很容易发现,但在更复杂的代码中可能更难检测到:
class Foo : public IFoo {
const Bar& bar_;
public:
Foo(const Bar& bar) : bar_(bar) {
}
void test() {
// access bar_ here
}
};
int baz() {
IFoo* foo = NULL;
if(whatever) {
Bar bar;
foo = new Foo(bar);
}
else {
// create other foo's
}
foo->test(); // segmentation fault
}
该错误是 Bar
立即超出范围,被销毁,然后在 foo->test()
中使用。一种解决方案是使用 Bar* bar = new Bar()
在堆上创建 Bar
。但是,我不喜欢这样做,因为我必须将 Bar* bar
指针保留在顶层,以便我可以在最后删除
它,即使 Bar
是特定于该特定代码块 if(whatever){}
的内容。
另一个解决方案是 boost::shared_ptr
if(whatever) {
boost::shared_ptr<Bar> bar(new Bar());
foo = new Foo(*bar);
}
因为 shared_ptr
也会立即超出范围,从而破坏所包含的对象。
简而言之,为了摆脱这个问题,我必须在任何地方使用 shared_ptr
,在 Foo
中作为成员变量,在 >Foo
的构造函数等。为了消除这些问题,我的所有 API 等都必须使用 shared_ptr
,这有点难看。但是,这样做是正确的吗?到目前为止,我有时会使用它来创建引用计数对象,但我的 API 中没有 shared_ptr
。您如何处理这个问题:一旦您使用了shared_ptr
,您就必须到处使用它?
(另外,如果您使用这些引用计数指针,您必须开始担心您是否真的想要 shared_ptr
还是 weak_ptr
等)
并且,我将使用什么作为相当于 Foo(const Bar& bar)
? Foo(const shared_ptr
?
当然,另一种选择是使用 pimpl
和您自己的计数器在 Bar 和其他对象中添加引用计数,但一般来说这太乏味了。
I recently had the following memory bug, which is easy to spot here, but can be harder to detect in more complex code:
class Foo : public IFoo {
const Bar& bar_;
public:
Foo(const Bar& bar) : bar_(bar) {
}
void test() {
// access bar_ here
}
};
int baz() {
IFoo* foo = NULL;
if(whatever) {
Bar bar;
foo = new Foo(bar);
}
else {
// create other foo's
}
foo->test(); // segmentation fault
}
The bug is that Bar
immediately goes out of scope, is destroyed and then used in foo->test()
. One solution is to create Bar
on the heap, using Bar* bar = new Bar()
. However, I don't like to do this because I'd have to keep the Bar* bar
pointer at top-level so I can access and delete
it at the end, even though Bar
is something that is specific to that particular code block if(whatever){}
.
Another solution is boost::shared_ptr<Bar>
, but I cannot just write this:
if(whatever) {
boost::shared_ptr<Bar> bar(new Bar());
foo = new Foo(*bar);
}
since the shared_ptr
goes out of scope immediately, too, destroying the contained object.
So in short, to get rid of this problem, I'd have to use shared_ptr
everywhere, in Foo
as member variable, in Foo
's constructor, etc. To eliminate these problems in general, all my APIs etc. have to use shared_ptr
, which is kind of ugly. But, is it the right thing to do? So far, I have used it sometimes to create reference-counted objects, but I have kept my APIs clean of shared_ptr
. How do you deal with this problem that, once you use shared_ptr
you have to use it everywhere?
(Also, if you use these reference-counted pointers, you have to start worrying about if you really want shared_ptr
or rather weak_ptr
etc.)
And, what would I use as an equivalent to Foo(const Bar& bar)
? Foo(const shared_ptr<const Bar> bar)
?
Another option, of course, is to add reference counting inside the Bar
and other objects yourself, using pimpl
and your own counters, but that gets too tedious as a general rule.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(6)
最好不要将 bar byref 传递到 Foo 中(换句话说,更改 Foos 构造函数),或者复制它,以便在 Foo 中保留一个副本。当然,在某些情况下这是不可能的。
关于使用 shared_ptr
覆盖代码,最简单的解决方案是将 shared_ptr
键入 BarPtr
或类似的。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我实际上会提出另一种解决方案...
我不太喜欢引用计数,不仅仅是混乱,而且还因为当多个对象拥有同一项目的句柄时很难推理。
现在你的代码可以工作了,因为我做了一个副本:)
当然,如果 Bar 不是多态的,那么它会容易得多。
那么,即使它没有使用参考,您确定您确实需要一个吗?
现在让我们偏离正轨,因为你做错了很多事情:
foo = new Foo(bar)
不太漂亮,你如何保证内存被删除,以防万一发生异常或在if
混乱中引入一些return
?您应该转向为您管理内存的对象auto_ptr
或来自 C++0x 或 Boost 的新unique_ptr
。Foo
不获取所有权,而不是使用引用计数?Foo(std::auto_ptrbar)
也可以。在不需要的地方回避引用计数。每次您分享某些内容时,您实际上会在代码中引入难以跟踪的错误来源(以及潜在的副作用)。这就是
Haskell
和函数式家族越来越受欢迎的原因:)I would actually propose another solution...
I don't really like reference counting that much, not just the clutter, but also because it's harder to reason when multiple objects have a handle to the same item.
And now your code works, because I made a copy :)
Of course, if Bar was NOT polymorphic, then it would be much easier.
So, even though it's not using a reference, are you sure you actually need one ?
Let's get off track now, because there are a number of things you do wrong:
foo = new Foo(bar)
ain't pretty, how are you going to guarantee that the memory is deleted in case an exception occurs or somewhat introduces somereturn
in theif
clutter ? You should move toward an object that manages memory for youauto_ptr
or the newunique_ptr
from C++0x or Boost.Foo
takes ownership ?Foo(std::auto_ptr<Bar> bar)
would work too.Shy from reference counting where it's not needed. Every time you share something you actually introduce a source of hard to track bugs in your code (and potentially side effects). That's why
Haskell
and the functional family are gaining popularity :)