为什么从函数返回“向量”是可以的?

请考虑这个代码。我已经见过这种类型的代码好几次了。words是一个局部向量。怎样才能从函数中返回它呢?

我们能保证它不会死吗?

 std::vector<std::string> read_file(const std::string& path)
{
std::ifstream file("E:\\names.txt");


if (!file.is_open())
{
std::cerr << "Unable to open file" << "\n";
std::exit(-1);
}


std::vector<string> words;//this vector will be returned
std::string token;


while (std::getline(file, token, ','))
{
words.push_back(token);
}


return words;
}
137586 次浏览

我们能保证它不会死吗?

As long there is no reference returned, it's perfectly fine to do so. words will be moved to the variable receiving the result.

The local variable will go out of scope. after it was moved (or copied).

C + + 前11:

该函数将不返回局部变量,而是返回它的一个副本。但是,编译器可能会在不执行实际复制操作的情况下执行优化。

详情请参阅 这个问题的答案

C + + 11:

该函数将移动该值。详细信息请参阅 这个答案

我认为你指的是 C (和 C + +)中不允许从函数返回数组(或者至少不会像预期的那样工作)的问题——这是因为数组返回将(如果你用简单的形式写它)返回一个指向堆栈上实际数组的指针,然后当函数返回时立即删除该指针。

但是在这种情况下,它可以工作,因为 std::vector是一个类,而且类和 structs 一样,可以(也将会)复制到调用者上下文。[实际上,大多数编译器都会使用一种叫做“返回值优化”的方法来优化这种特殊类型的副本,这种方法是专门为了避免在从函数返回大型对象时复制它们而引入的,但这是一种优化,从程序员的角度来看,它的行为就好像为对象调用了赋值构造函数一样]

只要不返回指针或对函数返回内容的引用,就没问题。

为了更好地理解这种行为,您可以运行以下代码:

#include <iostream>


class MyClass
{
public:
MyClass() { std::cout << "run constructor MyClass::MyClass()" << std::endl; }
~MyClass() { std::cout << "run destructor MyClass::~MyClass()" << std::endl; }
MyClass(const MyClass& x) { std::cout << "run copy constructor MyClass::MyClass(const MyClass&)" << std::endl; }
MyClass& operator = (const MyClass& x) { std::cout << "run assignation MyClass::operator=(const MyClass&)" << std::endl; }
};


MyClass my_function()
{
std::cout << "run my_function()" << std::endl;
MyClass a;
std::cout << "my_function is going to return a..." << std::endl;
return a;
}


int main(int argc, char** argv)
{
MyClass b = my_function();


MyClass c;
c = my_function();


return 0;
}

产出如下:

run my_function()
run constructor MyClass::MyClass()
my_function is going to return a...
run constructor MyClass::MyClass()
run my_function()
run constructor MyClass::MyClass()
my_function is going to return a...
run assignation MyClass::operator=(const MyClass&)
run destructor MyClass::~MyClass()
run destructor MyClass::~MyClass()
run destructor MyClass::~MyClass()

注意,这个示例是在 C + + 03上下文中提供的,可以对 C + + > = 11进行改进

这实际上是设计上的失败。您不应该对任何不是原语的东西使用返回值,对任何不是相对平凡的东西使用返回值。

理想的解决方案应该通过一个返回参数来实现,该参数决定引用/指针,并正确使用“常量 y”作为描述符。

除此之外,您应该意识到 C 和 C + + 中数组上的标签实际上是一个指针,它的订阅实际上是一个偏移量或加法符号。

因此,返回 foo [偏移量]的标签或 ptr array _ ptr = = = array 标签实际上是说返回元素位于内存指针位置 foo + 类型返回类型的偏移量。

我不同意,做 不推荐返回一个 vector:

vector <double> vectorial(vector <double> a, vector <double> b)
{
vector <double> c{ a[1] * b[2] - b[1] * a[2], -a[0] * b[2] + b[0] * a[2], a[0] * b[1] - b[0] * a[1] };
return c;
}

This is much faster:

void vectorial(vector <double> a, vector <double> b, vector <double> &c)
{
c[0] = a[1] * b[2] - b[1] * a[2]; c[1] = -a[0] * b[2] + b[0] * a[2]; c[2] = a[0] * b[1] - b[0] * a[1];
}

我在 VisualStudio2017上进行了测试,在发布模式下得到了以下结果:

8.01《议定书》/《公约》缔约方会议参考文件
5.09 MOP 返回矢量

在调试模式下,情况要糟糕得多:

参考0.053 MOPS
0.034按返回矢量分列的 MOP