Почему это нормально, чтобы вернуть вектор из функции?


пожалуйста, рассмотрите этот код. Я видел этот тип кода несколько раз. 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;
}
5 104

5 ответов:

можем ли мы гарантировать, что он не умрет?

пока ссылка не возвращается,это совершенно нормально. words будет перемещен в переменную, получающую результат.

локальная переменная выйдет из области видимости. после того, как он был перемещен (или скопирован).

Pre C++11:

функция не возвращает локальную переменную, а копию. Однако компилятор может выполнить оптимизацию, в которой не выполняется фактическое действие копирования.

посмотреть этот вопрос и ответ для более подробной информации

C++11:

функция переместит значение, см. ответ для более подробной информации

Я думаю, что вы имеете в виду проблему в C (и C++), что возврат массива из функции не допускается (или, по крайней мере, не будет работать так, как ожидалось) - это потому, что возврат массива (если вы пишете его в простой форме) возвращает указатель на фактический массив в стеке, который затем быстро удаляется, когда функция возвращается.

но в этом случае это работает, потому что std::vector - Это класс, и классы, такие как структуры, могут (и будут) копироваться в контекст вызывающих объектов. [На самом деле, большинство компиляторов оптимизируют этот конкретный тип копирования, используя что-то под названием "оптимизация возвращаемого значения", специально введенное, чтобы избежать копирования больших объектов, когда они возвращаются из функции, но это оптимизация, и с точки зрения программистов она будет вести себя так, как если бы конструктор присваивания был вызван для объекта]

пока вы не возвращаете указатель или ссылку на что-то, что находится внутри возвращаемой функции, вы в порядке.

чтобы хорошо понять поведение, вы можете запустить этот код :

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

Это на самом деле неудача дизайна, вы не должны использовать возвращаемое значение для чего-либо не примитивного для чего-либо, что не является относительно тривиальным. Идеальное решение должно быть реализовано через возвращаемый параметр с решением о ссылке / ptr и надлежащим использованием "const\'y\'ness" в качестве дескриптора.

кроме того, вы должны понимать, что метка на массиве в C и c++ фактически является указателем, а его подписка фактически является смещением или добавлением символ.

таким образом, метка или ptr array_ptr === метка массива, возвращающая foo[offset], действительно говорит о возврате элемента в памяти ptr location foo + offset типа return type.