如何在 C++ 方法中返回一个数组,我必须如何声明它? int[] 测试(无效); ??
这听起来像一个简单的问题,但在 C++ 中你有很多选择。首先,你应该更喜欢...
...因为他们为您管理内存,确保正确的行为并大大简化事情:
std::vector<int> fn()
{
std::vector<int> x;
x.push_back(10);
return x;
}
std::array<int, 2> fn2() // C++11
{
return {3, 4};
}
void caller()
{
std::vector<int> a = fn();
const std::vector<int>& b = fn(); // extend lifetime but read-only
// b valid until scope exit/return
std::array<int, 2> c = fn2();
const std::array<int, 2>& d = fn2();
}
创建对返回数据的const 引用的做法有时可以避免复制,但通常您可以只依赖返回值优化,或者 - 对于vector 而不是array - 移动语义(引入C++11)。
如果你真的想使用 inbuilt 数组(不同于上面提到的标准库类array),一种方法是让调用者保留空间并告诉函数使用它:
void fn(int x[], int n)
{
for (int i = 0; i < n; ++i)
x[i] = n;
}
void caller()
{
// local space on the stack - destroyed when caller() returns
int x[10];
fn(x, sizeof x / sizeof x[0]);
// or, use the heap, lives until delete[](p) called...
int* p = new int[10];
fn(p, 10);
}
另一种选择是将数组包装在一个结构中,与原始数组不同,它可以合法地从函数中按值返回:
struct X
{
int x[10];
};
X fn()
{
X x;
x.x[0] = 10;
// ...
return x;
}
void caller()
{
X x = fn();
}
从上面开始,如果你被 C++03 卡住了,你可能想把它概括为更接近 C++11 std::array:
template <typename T, size_t N>
struct array
{
T& operator[](size_t n) { return x[n]; }
const T& operator[](size_t n) const { return x[n]; }
size_t size() const { return N; }
// iterators, constructors etc....
private:
T x[N];
};
另一种选择是让被调用函数在堆上分配内存:
int* fn()
{
int* p = new int[2];
p[0] = 0;
p[1] = 1;
return p;
}
void caller()
{
int* p = fn();
// use p...
delete[] p;
}
为了帮助简化堆对象的管理,许多 C++ 程序员使用“智能指针”来确保在指向对象的指针离开其作用域时删除。使用 C++11:
std::shared_ptr<int> p(new int[2], [](int* p) { delete[] p; } );
std::unique_ptr<int[]> p(new int[3]);
如果你卡在 C++03 上,最好的选择是查看你的机器上是否有 boost 库:它提供了boost::shared_array。
另一种选择是让fn() 保留一些静态内存,尽管这不是线程安全的,这意味着每次调用fn() 都会覆盖任何保存先前调用指针的人看到的数据。也就是说,对于简单的单线程代码来说,它可以很方便(而且很快)。
int* fn(int n)
{
static int x[2]; // clobbered by each call to fn()
x[0] = n;
x[1] = n + 1;
return x; // every call to fn() returns a pointer to the same static x memory
}
void caller()
{
int* p = fn(3);
// use p, hoping no other thread calls fn() meanwhile and clobbers the values...
// no clean up necessary...
}