如何禁止或阻止堆栈分配变量的传递?

时间:2013-06-21 18:56:01

标签: c++ architecture stl

我有一个类使用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)

的论点

2 个答案:

答案 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*