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

时间:2014-03-26 08:18:53

标签: c++ vector stl scope standard-library

请考虑此代码。我已经多次看过这种类型的代码了。 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;
}

6 个答案:

答案 0 :(得分:101)

Pre C ++ 11:

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

有关详细信息,请参阅this question & answer

C ++ 11:

该函数将移动该值,有关详细信息,请参阅this answer

答案 1 :(得分:66)

  

我们可以保证它不会死吗?

只要没有返回引用,这样做就完全没问题了。 words将移动到接收结果的变量。

局部变量将超出范围。移动(或复制)之后。

答案 2 :(得分:24)

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

但是在这种情况下,它可以工作,因为std::vector是一个类,并且类(如结构)可以(并且将会)复制到调用者上下文。 [实际上,大多数编译器会使用名为&#34;返回值优化&#34;的东西来优化这种特定类型的副本,专门用于避免在从函数返回时复制大对象,但这是一个优化从程序员的角度来看,它的行为就像为对象调用赋值构造函数一样

只要你没有返回指针或对函数返回内容的引用,你就可以了。

答案 3 :(得分:12)

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

#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()

答案 4 :(得分:-2)

我不同意也不建议返回向量:

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;
}

这快得多:

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];
}

我在VS2017上进行了测试,并在发布模式下获得了以下结果:

8.01 MOP(参考) 5.09 MOP返回向量

在调试模式下,情况更糟:

通过参考

0.053 MOPS 返回向量为0.034 MOPs

答案 5 :(得分:-8)

这实际上是设计的失败,对于任何不是相对微不足道的事情,你不应该为任何不是原语的东西使用返回值。理想的解决方案应该通过返回参数来实现,该参数决定了参考/ ptr以及正确使用&#34; const \&#39; \ n&#39; ness&#34;作为描述符。

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

因此返回foo [offset]的标签或ptr array_ptr ===数组标签实际上是在内存ptr位置foo +返回类型返回类型的返回元素。