0

我有一个使用 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 接受堆栈分配的数据?有没有更好的方法来设计这个?


2013 年 6 月 21 日编辑

在 for 循环中包含delete _bar;andforward_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)

4

2 回答 2

2

简单地说,你不能。指针是指针。你应该首先避免它们。如果您选择使用它们,请创建文档策略并对其代码进行适当的审查。

在您的示例中,发生了所有权转移(或者至少一半的设计部分也很臭),您必须记录这一点。必须仅使用使用某些方式创建的对象调用该函数。&bar 必须在审查中发现违反了这一点。

于 2013-06-21T18:59:46.887 回答
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代表Bars 的所有权,所以添加BartoFoo只能由已经拥有Bar. 将这种独资表示为std::unique_ptr<Bar>一路创造,你有权删除的是unique_ptr,你无权删除的Bar*

于 2013-06-21T20:49:46.153 回答