Почему это нормально, чтобы вернуть вектор из функции?
пожалуйста, рассмотрите этот код. Я видел этот тип кода несколько раз. 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 ответов:
можем ли мы гарантировать, что он не умрет?
пока ссылка не возвращается,это совершенно нормально.
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.