Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C+中返回自动本地对象+; 我试图理解C++的一些方面。_C++_Return_Copy Constructor - Fatal编程技术网

在C+中返回自动本地对象+; 我试图理解C++的一些方面。

在C+中返回自动本地对象+; 我试图理解C++的一些方面。,c++,return,copy-constructor,C++,Return,Copy Constructor,我编写了这个简短的程序来展示从C++函数返回对象的不同方式: #include <iostream> using namespace std; // A simple class with only one private member. class Car{ private: int maxSpeed; public: Car( int ); void print(); Car& op

我编写了这个简短的程序来展示从C++函数返回对象的不同方式:

#include <iostream> 

using namespace std;

// A simple class with only one private member.
class Car{
     private:
        int maxSpeed;
     public:
        Car( int );
        void print();
        Car& operator= (const Car &);
        Car(const Car &);
 };

 // Constructor
 Car::Car( int maxSpeed ){
    this -> maxSpeed = maxSpeed;
    cout << "Constructor: New Car (speed="<<maxSpeed<<") at " << this << endl;
 }

 // Assignment operator
 Car& Car::operator= (const Car &anotherCar){
    cout << "Assignment operator: copying " << &anotherCar << " into " << this << endl;
    this -> maxSpeed = anotherCar.maxSpeed;
    return *this;
 }

 // Copy constructor
 Car::Car(const Car &anotherCar ) {
    cout << "Copy constructor: copying " << &anotherCar << " into " << this << endl;
    this->maxSpeed = anotherCar.maxSpeed;
 }

 // Print the car.
 void Car::print(){
    cout << "Print: Car (speed=" << maxSpeed << ") at " << this << endl;
 }

 // return automatic object (copy object on return) (STACK)
 Car makeNewCarCopy(){
    Car c(120);
    return c; // object copied and destroyed here
 }

// return reference to object (STACK)
Car& makeNewCarRef(){
    Car c(60);
    return c; // c destroyed here, UNSAFE!
    // compiler will say: warning: reference to local variable ‘c’ returned
 }

// return pointer to object (HEAP)
Car* makeNewCarPointer(){
    Car * pt = new Car(30);
    return pt; // object in the heap, remember to delete it later on!
 }

int main(){
    Car a(1),c(2);
    Car *b = new Car(a);
    a.print();
    a = c;
    a.print();

    Car copyC = makeNewCarCopy(); // safe, but requires copy
    copyC.print();

    Car &refC = makeNewCarRef(); // UNSAFE
    refC.print();

    Car *ptC = makeNewCarPointer(); // safe
    if (ptC!=NULL){
        ptC -> print();
        delete ptC;
    } else {
        // NULL pointer
    }
}
现在,我有以下问题:

  • makeNewCarCopy安全吗?是否在函数结束时复制和销毁本地对象?如果是这样,为什么不调用重载赋值操作符呢?它是否调用默认的复制构造函数
  • 我的直觉告诉我使用<代码> MKENEWCARPOCHECUT/COMPUT>作为从C++函数/方法返回对象的最常用方式。我说得对吗
      是的,
      makeNewCarCopy
      是安全的。理论上,当函数退出时会有一个副本,但因为编译器被允许删除该副本

      实际上,这意味着
      makeNewCarCopy
      将有一个隐藏的第一个参数,该参数是对未初始化的
      Car
      的引用,而
      makeNewCarCopy
      内部的构造函数调用将实际初始化驻留在函数堆栈框架之外的
      Car
      实例

      至于第二个问题:返回必须释放的指针不是首选方法。这是不安全的,因为函数如何分配
      Car
      实例的实现细节被泄露了,调用方需要清理它。如果您需要动态分配,那么我建议您返回一个
      std::shared\u ptr

      makeNewCarCopy安全吗?是否正在复制和销毁本地对象 在函数的末尾?如果是这样的话,为什么不调用重载 分配操作员?它是否调用默认的复制构造函数

      这里的重要问题是“makeNewCarCopy安全吗?”该问题的答案是“是”。您正在制作对象的副本并按值返回该副本。您不会试图返回对本地自动对象的引用,这在新手中是一个常见的陷阱,这很好

      这个问题的其他部分的答案就不那么重要了,尽管一旦您知道如何安全地完成这项工作,它们可能会在生产代码中变得至关重要。您可能看到也可能看不到局部对象的构造和破坏。事实上,您可能不会,尤其是在启用优化的情况下编译时。原因是编译器知道您正在创建一个临时文件并返回该文件,而该文件又被复制到其他地方。从某种意义上说,临时副本变得毫无意义,因此编译器跳过了整个烦人的create-copy-destroy步骤,直接在变量中构造新副本,这是它最终想要的。这就是所谓的。编译器可以对您的程序进行任何和所有更改,只要可观察到的行为与未进行任何更改相同(请参见:),即使复制构造函数有副作用(请参见:)

      我的直觉告诉我使用makeNewCarPointer作为最常用的方法 从C++函数/方法返回对象。我说得对吗

      不,考虑复制删减,正如我上面描述的那样。所有当代的主要编译器都实现了这种优化,并且做得非常好。所以,如果您可以像按指针复制一样高效地(至少)按值复制,那么按指针复制在性能方面有什么好处吗

      答案是否定的。如今,你通常希望按价值回报,除非你有迫切的需要不这样做。在这些引人注目的需求中,当您需要返回的对象超过创建它的“范围”时——但性能不在其中。事实上,动态分配在时间上比自动(即“堆栈”)分配要昂贵得多。

      • makeNewCarCopy
        是安全的。在大多数情况下,它是有效的,因为编译器可以进行某些优化,例如(您没有看到调用赋值运算符或复制构造函数的原因)和/或C++11添加的优化
      • makeNewCarPointer
        可能非常有效,但同时也非常危险。问题是您很容易忽略返回值,编译器不会产生任何警告。因此,至少应该返回智能指针,如
        std::unique\u ptr
        std::shared\u ptr
        。但以前的方法更可取,至少不会慢。如果由于不同的原因必须在堆上创建对象,情况就不同了

      1)您将获得副本省略。2) 不,最自然的方法是按值返回。
      std::unique_ptr
      通常比
      std::shared_ptr
      @Yakk更好。我发现
      unique_ptr
      具有不必要的限制,它唯一更好的地方就是性能。我从来没有想过“我真希望我在这里使用了一个
      独特的ptr
      !”。我只在它从未离开类/模块时才使用
      unique\u ptr
      ,这里不是这种情况。
      shared\u ptr
      的问题是,它的生存期和所有权现在不清楚。在几乎所有情况下,一个对象都应该由另一个数据结构所拥有:当一个对象由多个数据结构所拥有时,您往往会得到相当于意大利面条代码的资源管理
      shared_ptr
      表示对象生命周期的共享管理和所有权,这是一种特殊情况,不应该是默认情况。是的,它让你做的事情远不止是独一无二的,但其中很多都是坏习惯@雅克我想我们同意,但我们对目前的情况有误解。我考虑<代码> MKENEWWCARIOS一个公共库函数,它的任务是创建代码< CAR> > <代码> s。使用
      unique_ptr
      shared_ptr
      与所有权、架构、接口契约以及持有它的对象无关。是的,您可以拒绝使用
      shared_ptr的任何功能
      
      Constructor: New Car (speed=1) at 0x7fff51be7a38
      Constructor: New Car (speed=2) at 0x7fff51be7a30
      Copy constructor: copying 0x7fff51be7a38 into 0x7ff60b4000e0
      Print: Car (speed=1) at 0x7fff51be7a38
      Assignment operator: copying 0x7fff51be7a30 into 0x7fff51be7a38
      Print: Car (speed=2) at 0x7fff51be7a38
      Constructor: New Car (speed=120) at 0x7fff51be7a20
      Print: Car (speed=120) at 0x7fff51be7a20
      Constructor: New Car (speed=60) at 0x7fff51be79c8
      Print: Car (speed=60) at 0x7fff51be79c8
      Constructor: New Car (speed=30) at 0x7ff60b403a60
      Print: Car (speed=30) at 0x7ff60b403a60