C ++(或任何其他语言)的优雅控制流程

时间:2011-08-30 04:34:39

标签: c++

我正在编写一个具有许多返回点的函数(取决于条件是什么),并且它在不同点处执行了一堆new个。在每个返回点,我需要做的delete集合是不同的。即便如此,我也不想在不同的地方做这些。处理这个问题的好方法是什么?

一些细节:让我们考虑一个功能:

int MainClass::testFunction() {
  numThreads++;
  char *a = new char[100];
  // Some computation with a
  if (condition1) {
    numThreads--;
    return -1;
  } 
  char *b = new char[100];
  // Some computation with b
  if (condition2) {
    numThreads--;
    return 42;
  } 
  // Some more stuff. 
  numThreads--;
}

现在,在return -1之前,我需要在delete a之前执行return 42,我需要delete a; delete b;。如果我有多个返回点,你可以想象这会变得多么复杂。

以下是我的解决方案:

第一个解决方案:将所有删除放在函数末尾,放入一些标签,将返回值存储在返回点,然后使用goto(是的,那个脏词!)跳转到适当的删除并返回执行那些删除后。

在上面的例子中,我可以说

superset:
  delete b;
subset:
  delete a;
numThreads--;

goto superset放在return 42goto subset之前return -1

出于明显的原因,我不喜欢这个解决方案! :-)

第二个解决方案:我可以构建一个内部类实例,并对该类实例的变量执行new。像这样......

int MainClass::testFunction() {
  class Local {
    char *a, *b;
    Local () : a(NULL), b(NULL) {}
    ~Local () { if (a != NULL) delete a; if (b != NULL) delete b; }
  };
  Local l = Local();
  l.a = new char[100];
  // Some computation with a
  if (condition1) {
    return -1;
  } 
  l.b = new char[100];
  // Some computation with b
  if (condition2) {
    return 42;
  } 
}

那么,问题是什么?那么,我如何访问方法中的numThreads变量?我想在numThreads++的{​​{1}}和Local的构造函数中numThreads--进行Local。如果有帮助,testFunction也是另一个类的成员函数。

感谢阅读。

更新:在堆栈上分配数组肯定是一种可能,但我遇到堆栈溢出(啊...这个网站的名称:-))在堆栈上进行大量分配(堆栈)线程大小默认为2MB)。我想在这个问题中解决的是一般资源获取和销毁。

5 个答案:

答案 0 :(得分:9)

了解RAII

基本上,除了在构造函数(或赋值)中之外,永远不要使用new,除了在析构函数中之外,永远不要使用delete

关于您的具体情况,您可以执行以下操作:

(1)只需使用std::vector<char> (2)改为char a[100];(这是堆栈分配,因此自动收集)。这仅在100为常量时才有效。您也可以将std::array<char, 100>与C ++ 11编译器一起使用(如果安装了增强库,则使用boost::array<char, 100>。) (3)使用alloca()在堆栈上分配空间(如果100不是常数)(请注意这一点)。
(4)编写自己的类,在构造函数中使用new分配内存,并在析构函数中使用delete删除内存。

我建议(2)100是常数而不是太大,否则(1)。

答案 1 :(得分:4)

  

处理此问题的好方法是什么?

#include <vector>
int MainClass::testFunction() {
  numThreads++;
  std::vector<char> a(100);
  // Some computation with a
  if (condition1) {
    numThreads--;
    return -1;
  } 
  std::vector<char> b(100);
  // Some computation with b
  if (condition2) {
    numThreads--;
    return 42;
  } 
  // Some more stuff. 
  numThreads--;
}

答案 2 :(得分:2)

庵。你太复杂了。只需在开头将ab设置为NULL即可。用try / catch围绕整个事物。如果出现任何问题,扔东西(什么都行)。在catch块中,在所有变量上调用delete。如果变量为NULL,delete将不执行任何操作。

如果你需要做返回变量的东西,理论上你只能throw返回值(是的,你可以抛出整数)。然后当你完成清理时,只需返回抛出的值。

char *a = NULL, *b = NULL;

try
{
    a = ...;
    if(bad_thing)
        throw -1;

    b = ...;
    throw 42;
}
catch(int e)
{
    delete[] a;
    delete[] b;
    return e;
}

答案 3 :(得分:0)

int MainClass::imp_testFunction() {

// perhaps break up a-compute, b-compute, some more stuff to
// separate methods if they are nontrivial.

// 100 chars should go on the stack (something like boost::array
// is ideal if you can use that), unless you know you are
// performing deep/recursive calls or have a small stack
// (e.g. embedded). for large or variable sized allocations,
// use something like a std::vector.
    char a[100];

// Some computation with a
    if (condition1) {
        return -1;
    }

    char b[100];
// Some computation with b
    if (condition2) {
        return 42;
    }
// Some more stuff.
}

int MainClass::testFunction() {
   // refactor this so you don't need to inc/dec at each exit.
    ++numThreads;
    const int ret(imp_testFunction());
    --numThreads;
    return ret;
}

答案 4 :(得分:0)

如果你必须使用这个控制流与所有这些回报,一个解决方案可能是使用智能指针:

int MainClass::testFunction() {
  numThreads++;
  std::unique_ptr<char *> a(new char[100]);
  // Some computation with a
  if (condition1) {
    numThreads--;
    return -1;
  } 
  std::unique_ptr<char *> b(new char[100]);
  // Some computation with b
  if (condition2) {
    numThreads--;
    return 42;
  } 
  // Some more stuff. 
  numThreads--;
}

在最糟糕和最奇怪的情况下,保持当前的控制流并且不移动a或b它们将在退出testFunction时被释放。