c++ - 在堆上分配内存的函数原型(prototype) (C/C++)

标签 c++ c buffer heap-memory

我是 C++ 的新手,所以这可能是一个初学者问题。它考虑了做一些我怀疑相当普遍的事情的“适当”风格。​​

我正在编写一个函数,该函数在履行其职责时会在堆上分配内存以供调用者使用。我很好奇这个函数的好的原型(prototype)应该是什么样子。现在我有:

int f(char** buffer);

要使用它,我会写:

char* data;
int data_length = f(&data);
// ...
delete[] data;

但是,我将一个指针传递给一个指针这一事实提示我,我可能以错误的方式执行此操作。

有没有人愿意开导我?

最佳答案

在 C 中,这或多或少是合法的。

在 C++ 中,函数通常不应该这样做。你应该尝试使用 RAII以保证内存不会泄漏。

现在您可能会说“它怎么会泄漏内存,我就在那里调用 delete[]!”,但是如果 // ... 抛出异常怎么办?线条?

根据函数的确切用途,您可以考虑多种选择。一个明显的方法是用 vector 替换数组:

std::vector<char> f();

std::vector<char> data = f();
int data_length = data.size();
// ...
//delete[] data; 

现在我们不再需要显式删除,因为 vector 是在堆栈上分配的,当它超出范围时会调用它的析构函数。

我应该提一下,作为对评论的回应,上面的内容暗示了 vector 的拷贝,这可能会很昂贵。大多数编译器会,如果 f功能不是太复杂,优化那个拷贝,这样就可以了。 (如果函数调用不频繁,开销将不会很重要无论如何)。但如果这没有发生,您可以将一个空数组传递给 f通过引用函数,并且有f将其数据存储在其中,而不是返回一个新 vector 。

如果返回拷贝的性能 Not Acceptable ,另一种选择是完全解耦容器的选择,并改用迭代器:

// definition of f
template <typename iter>
void f(iter out);

// use of f
std::vector<char> vec;
f(std::back_inserter(vec));

现在可以使用通常的迭代器操作(*out 引用或写入当前元素,++out 将迭代器向前移动到下一个元素)——更重要的是,所有标准算法现在都将工作。你可以使用 std::copy例如,将数据复制到迭代器。这是标准库通常选择的方法(即,这是一个好主意;))当函数必须返回数据序列时。

另一种选择是让您自己的对象负责分配/解除分配:

struct f { // simplified for the sake of example. In the real world, it should be given a proper copy constructor + assignment operator, or they should be made inaccessible to avoid copying the object
  f(){
    // do whatever the f function was originally meant to do here
    size = ???
    data = new char[size];
  }
  ~f() { delete[] data; }

int size;
char* data;
};

f data;
int data_length = data.size;
// ...
//delete[] data; 

同样,我们不再需要显式删除,因为分配是由堆栈上的对象管理的。后者显然需要更多的工作,并且有更多的错误空间,所以如果标准 vector 类(或其他标准库组件)可以完成这项工作,则更喜欢它们。此示例仅在您需要根据您的情况进行定制的情况下使用。

C++ 中的一般经验法则是“如果您在 RAII 对象之外编写 deletedelete[],那么您就错了。如果您正在编写 new 或 `new [] 在 RAII 对象之外,你做错了,除非结果立即传递给智能指针”

关于c++ - 在堆上分配内存的函数原型(prototype) (C/C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1171923/

相关文章:

iphone - 为什么此 Objective-C 代码会引发 malloc 错误?

c - 使用 getchar() 时,为什么首先需要清除输入键的缓冲区?

python - ctypes 中的 const void* 指针

vim - MacVim : share named registers across windows?

c++ - 创建共享库时发生核心转储

c++ - 不同编译器的不同输出 - C 和 C++

c++十进制转二进制,然后用运算,再转回十进制

c - 这个 _itoa_s 失败的技术原因是什么?

c++ - #include QtWebKit (Qt4) 或 QtWebKitWidgets (Qt<5.6) 或 QtWebEngineWidgets (Qt>=5.6)

c++ - 在 C/C++ 应用程序中使用 Fortran90 模块