HOUR 13 Developing Advanced References and Pointer

Posted a-cock

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HOUR 13 Developing Advanced References and Pointer相关的知识,希望对你有一定的参考价值。

Passing by Reference for Efficiency

传统的传值方法,参数传入时,执行一次copy,函数返回时,又一次copy执行,这样很消耗内存,运行效率慢。C++引入了copy constructor 可以解决这个问题。

下面的代码演示上面的这句话:定义一个SimpleCat类,创建两个函数,分别通过pass by value 和 pass by reference OR pointer, 返回指针。 传reference不需要复制对象,缺点是把原对象直接暴露在被调函数中。

#include <QCoreApplication>
#include <iostream>

class SimpleCat
{
public:
    SimpleCat();
    SimpleCat(SimpleCat&);
    ~SimpleCat();
};

SimpleCat::SimpleCat()
{
    std::cout << "SimpleCat Constructor Performed ..." << std::endl;
}
SimpleCat::SimpleCat(SimpleCat&)
{
    std::cout << "SimpleCat Copy Constructor Performed ..." << std::endl;
}
SimpleCat::~SimpleCat()
{
    std::cout << "SimpleCat Destructor Performed ..." << std::endl;
}

SimpleCat functionOne(SimpleCat srcCat);
SimpleCat *functionTwo(SimpleCat *srcCat);

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::cout << "Making a cat ..." << std::endl;

    SimpleCat Frisky;
    std::cout << "\\n\\n\\n\\n\\n";
    std::cout << "\\n\\n\\n\\n\\n";
    std::cout << "Calling functionOne ..." << std::endl;
    functionOne(Frisky);

    std::cout << "\\n\\n\\n\\n\\n";
    std::cout << "\\n\\n\\n\\n\\n";
    std::cout << "Calling functionTwo ..." << std::endl;
    functionTwo(&Frisky);

    return a.exec();
}



//FunctionOne pass by value
SimpleCat functionOne(SimpleCat srcCat)
{
    std::cout << "Function one. Returning ..." << std::endl;
    return srcCat;
}
//FunctionTwo pass by pointer
SimpleCat *functionTwo(SimpleCat *srcCat)
{
    std::cout << "Function two. Returning ..." << std::endl;
    return srcCat;
}

执行结果如下图:

技术分享图片

 函数1:

  1. main函数传值给函数1,相当于复制一个object给被调函数,所以复制构造函数被执行->SimpleCat Copy Constructor Performed ... 这里srcCat的存储位置在stack
  2. 函数1执行-> function one returning 
  3. 函数1返回object给主函数(传值复制方式),再一次调用复制构造函数,把处理后的object复制给主函数。
  4. 第三步里子函数向主函数复制object时,产生临时对象(tempObject 我们看不见),在返回结束后被销毁,所以执行了一次constructor和destructor
  5. 函数1返回后,该函数结束,srcCat 生命周期结束,调用destructor

函数2:

  1. 主函数向子函数传递参数使用reference,未调用constructor
  2. 子函数向主函数返回的也是reference(返回值srcCat实际上是Frisky的地址)

传值方式,调用两次复制构造函数和两次析构函数,然后传reference方式一次也不调用

Pass a const Pointer

为什么?

上面的函数2,效率挺高,但是存在风险。直接把地址给了子函数,子函数可以为所欲为,通常主函数不想改变原始值。传值方式提供了这种保护,不过太蠢了,效率太慢了。

既想要传值方式的安全,又想要传引用方式的效率——传const pointer

#include <QCoreApplication>
#include <iostream>

class SimpleCat
{
public:
    SimpleCat();
    SimpleCat(SimpleCat&);
    ~SimpleCat();

    int getAge() const {return itsAge;}
    void setAge(int age)  {itsAge = age;}

private:
    int itsAge;
};

SimpleCat::SimpleCat()
{
    std::cout << "SimpleCat Constructor Performed ..." << std::endl;
    itsAge = 1;
}
SimpleCat::SimpleCat(SimpleCat&)
{
    std::cout << "SimpleCat Copy Constructor Performed ..." << std::endl;
}
SimpleCat::~SimpleCat()
{
    std::cout << "SimpleCat Destructor Performed ..." << std::endl;
}

const SimpleCat & functionTwo(const SimpleCat & srcCat);
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    std::cout << "Making a cat ..." << std::endl;

    SimpleCat Frisky;
    std::cout << "Frisky is " << Frisky.getAge()
              << "years old" << std::endl;

    int age = 5;
    Frisky.setAge(age);
    std::cout << "Frisky is " << Frisky.getAge()
              << "years old" << std::endl;

    std::cout << "Calling FunctionTwo ..." << std::endl;
    functionTwo(Frisky);
    std::cout << "Frisky is " << Frisky.getAge()
              << "years old" << std::endl;
    return 0;


    return a.exec();
}


//函数进来指向常对象的引用,函数返回指向常对象的引用
//FUC2 takes and returns a reference to a constant object
const SimpleCat & functionTwo(const SimpleCat &srcCat)
{
    std::cout << "Function Two. Returning..." << std::endl;
    std::cout << "Frisky is now" << srcCat.getAge()
              << "years old" << std::endl;
    //srcCat.setAge(8);

    return srcCat;
}

注意高亮部分,主次被注释掉的语句,如果takes a reference to a constant object,就不可以修改了,这样就达到了安全的目的,至于函数2最前面的那个const我就不知道啥意思了

什么时候用引用,什么时候用指针?

引用用起来方便,能用就尽量用

引用只能被赋值一次,所有如果要多次赋值,就用指针。引用不可以为NULL,所有如果有不确定对象,用指针

不可以返回对局部变量的引用

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Man &rMan = theFunction();
    std::cout << "rMan is " << rMan.getAge() << " years old!" << std::endl;
    return 0;

    return a.exec();
}


Man &theFunction()
{
    Man bob(5,9);
    return bob;
}

编译也许会通过,但是一定会系统崩溃。

返回对heap上对象的引用

Man &theFunction();

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Man &rMan = theFunction();
    std::cout << &rMan << std::endl;
    std::cout << "rMan is " << rMan.getAge() << " years old!" << std::endl;
    return 0;

    return a.exec();
}


Man &theFunction()
{
    Man *pBob = new Man(5,9);
    std::cout << pBob << std::endl;
    return *pBob;
}

技术分享图片

执行结果,可以看到,即使在theFunction域外,堆上的这个对象存活了下来,函数返回后还可以使用。

 

这节课太难了……

 

以上是关于HOUR 13 Developing Advanced References and Pointer的主要内容,如果未能解决你的问题,请参考以下文章

概念辨析-Hardware Description还是Hardware Developing?

CF581C Developing Skills 模拟

Developing Vert.x Modules with Gradle

在 WordPress-Developing 中寻找解决方案

Developing crm service based on apache cxf

-DEVELOPING THE FIRST NODE .2