我有一个类使用std :: forward_list,如下所示:
void Foo::AddBar(Bar* _bar)
{
Bars.push_front(_bar);
}
void Foo::DeleteBar(Bar* _bar)
{
for (forward_list::iterator index = Bars.begin(); index != Bars.end(); ++index)
{
if (_bar == *index)
{
delete _bar;
forward_list.remove(_bar);
}
}
}
如果我传递一个堆栈分配变量,在调试/发布中它会给我一个运行时错误,在生产中它会“破坏”堆。
Bar bar;
foo.AddBar(&bar);
foo.DeleteBar(&bar); // Memory corruption on "delete _bar"
如何防止Foo :: AddBar接受堆栈分配的数据?有没有更好的方法来设计它?
修改 6/21/13
在for循环中包含delete _bar;
和forward_list.remove(_bar);
会在迭代器递增时导致运行时错误。
我选择将所有权控制完全保留在Foo中并使用如下模板:
template<class T> T* AddBar()
{
Bar* object = new T();
Bars.push_front(object);
return object;
}
// Usage looks like...
Process* pid = foo.AddBar<MyBar>(); // adding a subclass of Bar
我正在使用指针作为PID - 用于查找目的。我总是可以返回int
以防止用户在没有首先投射的情况下delete
。哦,我可以做AddBar(void* arguments)
答案 0 :(得分:2)
简单地说,你不能。指针是一个指针。你应该首先避免它们。如果您选择使用它们,请创建文档策略并对其进行适当的审核。
在您的示例中,所有权转移发生(或者至少在设计的某一部分发生故障的情况下),您必须记录下来。必须仅使用以某些方式创建的对象调用该函数。 &amp; bar必须在评论中被视为违反该条款。
答案 1 :(得分:1)
更改您的界面和实施以使用unique_ptr
。
虽然用户仍然可以将其堆栈指针包装在unique_ptr
中,但至少可以明显看出这种情况发生了。
struct Foo {
typedef std::vector< std::unique_ptr<Bar> > bar_storage;
bar_storage bars;
Bar* AddBar( std::unique_ptr<Bar> );
void DeleteBar( Bar* bar );
};
void Foo::AddBar(std::unique_ptr<Bar> bar)
{
Bars.push_back(std::move(bar));
}
void Foo::DeleteBar(Bar* bar)
{
for (bar_storage::iterator index = Bars.begin(); index != Bars.end(); ++index)
{
if (bar == *index)
{
Bars.erase(index);
}
}
}
我所做的是将未定义的行为推送到调用站点,特别是:
Bar bar;
foo.AddBar(&bar); // does not compile
相反,调用者被迫:
foo.AddBar(std::unique_ptr<Bar>(&bar)); // user just did something really vulgar!
foo.DeleteBar(&bar); // Memory corruption on "delete _bar"
特别是,因为您的foo
代表Bar
的所有权,所以Bar
添加到Foo
只能由已拥有Bar
的代码完成1}}。将此类唯一所有权代表std::unique_ptr<Bar>
一直追溯到创作,而您有权删除的内容为unique_ptr
,而您不具有的权限为Bar*
。