#include <iostream>

struct person_t{
        int age;
};

person_t get_person1(){
        person_t person;
        person.age = 10;
        return person;
}

person_t * get_person2(){
        person_t *person = new person_t;
        person->age = 20;
        return person;
}

int main(){
        person_t person1 = get_person1();
        person_t *person2 = get_person2();
        std::cout << person1.age << std::endl;
        std::cout << person2->age << std::endl;
        delete person2;
        return 0;
}

Chcę wiedzieć, jaki jest najbezpieczniejszy sposób zwrotu struktury z funkcji.

Jak w odpowiedzi na pytania w tutaj i Oto, mówi się, że kiedy ty Utwórz obiekt jak w get_person1(), ten obiekt zostanie zniszczony po tym, jak wychodzi z zakresu.

Ale kiedy szukam "Jak zwrócić strukturę z funkcji C ++", sugeruje mi metodę (z get_person1()) (przykład tutaj). Ale myślę, że ta metoda zniszczy obiekt po wywołaniu funkcji i myślę, że metoda 2 jest najbezpieczniejsza.

Czy jestem tutaj ..? Lub każda opinia dotycząca tego tematu ..?

Dziękuję Ci!!

11
Ramesh-X 10 luty 2018, 12:59

3 odpowiedzi

Mówi się, że po utworzeniu obiektu jak w get_person1(), ten obiekt zostanie zniszczony po tym, jak wychodzi z zakresu.

To, co jest zniszczone, jest obiektem lokalnym (tj.: person wewnątrz get_persion1()). Co jest zwracane, jest kopiowaniem tego obiektu: struct person_t jest kopiowany (może być również przemieszczany). Więc jest bezpieczny.


get_person2() jest również bezpieczny, ale rozważ przy użyciu inteligentne wskaźniki zamiast surowe wskaźniki

std::unique_ptr<person_t> get_person2(){
        auto person = std::make_unique<person_t>();
        // For pre-C++14
        // std::unique_ptr<person_t> person(new person_t);
        person->age = 20;
        return person;
}

W ten sposób dzwoniący do get_person2() nie musi dzwonić delete (może to zrobić).

4
眠りネロク 10 luty 2018, 10:17

Oba podejścia są równie bezpieczne - ani jeden z nich nie powoduje niezdefiniowanego zachowania, a wartość ustawiona wewnątrz funkcji przywraca do rozmówcy.

Główną różnicą jest to, że pierwsze podejście kopiuje struct, podczas gdy drugie podejście kopiuje wskaźnik do struct. Kiedy struct jest malutki, na przykład w swoim przykładzie, nie ma różnicy. Gdy struct staje się duże, zwracanie wskaźnika może zaoszczędzić kilka cykli procesora na koszt dodatkowej alokacji pamięci, więc jest daleko od bycia gwarantowaną wygraną.

Oczywiście, drugie podejście ma kolejną wadę, która ma delete w końcu struct. Pierwsze podejście jest wolne od tego wymogu.

4
Jason Aller 11 luty 2018, 04:22

Obie metody są bezpieczne.

Metoda 1 jest bezpieczna, ponieważ lokalny person jest kopiowany z zakresu funkcji. Często, Optymalizacja wartości powrotu (RVO) może być użyta do uniknięcia kopiowania.

Metoda 2 jest również bezpieczna, ponieważ pamięć dla instancji person jest przydzielana w sterty. Przydział ten jest oczywiście ważny poza zakresem funkcji. Musisz jednak pamiętać, aby zapomnieć o wspomnianej pamięci, gdy skończysz go używać. Nie jest to krytyczne w twoim przykładowym kodzie. Kupie alokacje są automatycznie ustalane, gdy główny kończy się, więc dla krótkiego przykładu nie "potrzebujesz" {{x1} }.

Twoje pytanie brzmi, które z tych metod jest "najbezpieczniej". Nie jest to możliwe, aby odbierać obiektywnie, chociaż kłóciłbym się, że szeroka większość programistów C ++ doradziłaby się z metodą 2 na korzyść metody 1. Wielu programistów C ++ zalecaliby przy użyciu inteligentnych wskaźników.

Uwaga końcowa: Metoda 1 i metoda 2 są zasadniczo różne. Przydzielanie pamięci na stosie (metoda 1) w porównaniu do pamięci alokacji na sterty (metoda 2) to dwie różne koncepcje. Istnieje wiele uwag, ale "bezpieczeństwo" rozważania.

2
Joakim Thorén 10 luty 2018, 18:42