我正在编写一个具有许多返回点的函数(取决于条件是什么),并且它在不同点处执行了一堆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 42
和goto 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)。我想在这个问题中解决的是一般资源获取和销毁。
答案 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)
庵。你太复杂了。只需在开头将a
和b
设置为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时被释放。