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

How do I disallow or block the passing of stack allocated variables?

本文关键字:堆栈 分配 变量 何禁止 禁止      更新时间:2023-10-16

我有一个类使用std::forward_list,比如so:

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;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,以防止用户在不首先强制转换的情况下进行deleteing。哦,对于参数,我可以执行AddBar(void* arguments)

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

在你的例子中,所有权的转移发生了(或者至少在设计的一半也很糟糕),你必须记录下来。必须仅使用使用特定方式创建的对象来调用函数&酒吧违反了这一规定,必须在审查中予以追究。

更改接口和实现以使用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的所有权,所以向Foo添加Bar只能由已经拥有Bar的代码完成。将这种唯一所有权表示为std::unique_ptr<Bar>,一直到创建,您有权删除的是unique_ptr,而您没有删除的则是Bar*