什么是安全的?从函数返回结构或指针

时间:2018-02-10 09:59:28

标签: c++ function struct return

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

我想知道从函数返回结构的最安全的方法是什么。

正如在herehere中对问题的回答一样,据说当你在get_person1()中创建一个对象时,该对象会在它熄灭后被销毁范围。

但是当我搜索“如何从函数c ++返回结构”时,它建议我使用方法一(使用get_person1())(示例here)。但我认为该方法会在调用函数后销毁对象,我认为方法2是最安全的。

我在这里错了..?或者关于这个话题的任何意见..?

谢谢!

4 个答案:

答案 0 :(得分:8)

使用按值返回有三个原因:

  • 它使您的代码可读
  • 这里的结构很小(一个int)所以它就像返回一个int。你可以用C ++做到这一点,效率很高
  • 在C ++ 17(以及之前的大多数编译器)中,将避免对象的中间副本的成本。它被称为RVO。您只需在 get_person 功能中添加一个回报。

答案 1 :(得分:4)

  

据说当你在get_person1()中创建一个对象时,该对象将在超出范围后被销毁。

销毁的是本地对象(即person内的get_persion1())。返回的是该对象的副本:复制struct person_t(也可以移动它)。所以,这是安全的。

get_person2()也是安全的,但请考虑使用智能指针而不是原始指针

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

这样,get_person2()的来电者不必致电delete(可能会忘记这样做)。

答案 2 :(得分:4)

两种方法都同样安全 - 两者都不会导致未定义的行为,并且函数内部设置的值会使其返回给调用者。

主要区别在于第一种方法复制struct,而第二种方法复制指向struct的指针。当struct很小时,例如在您的示例中,没有区别。当struct变大时,返回指针可能会以额外的内存分配为代价来节省一些CPU周期,因此远远不能保证获胜。

显然,第二种方法有另一个缺点,即最终必须delete struct。第一种方法不受此要求的限制。

答案 3 :(得分:2)

这两种方法都是安全的。

方法1是安全的,因为从函数范围复制了本地person。通常,Return Value Optimization (RVO)可用于避免复制。

方法2也是安全的,因为person实例的内存是在堆中分配的。这种分配显然在函数范围之外有效。但是,您必须记住在完成使用后释放所述内存。这在您的示例代码中并不重要。 Heap-allocations are automatically deallocated when main terminates,所以对于您的简短示例,您实际上“不需要”delete person2

您的问题是哪种方法“最安全”。虽然我认为绝大多数C ++程序员会建议方法2支持方法1,但这是不可能客观回答的。许多C ++程序员会建议使用智能指针。

最后评论:方法1和方法2根本不同。在堆栈上分配内存(方法1)与在堆上分配内存(方法2)是两个不同的概念。 There are many more considerations to make but "safety" considerations