9

我正在研究c ++的引用,现在我对变量名和引用之间的区别感到很困惑。测试代码如下:

class TestClass{
private:
    int num;
public:
    TestClass(int n):num(n){
        cout<<this<<" : init of : " <<this->num<<endl;
    }

    TestClass(const TestClass& t):num(t.num){
        cout<<this<<" : copyInit of : " <<this->num<<endl;
    }

};

int main(int argc, const char * argv[]){

    TestClass t = *(new TestClass(55)); //just to test copy initialization

    const TestClass t2 = TestClass(100); //option1
    const TestClass &t2 = TestClass(100); //option2


}

所以现在我有两个制作对象的选择,它们是相互排斥的。

据我了解,如果我使用options2,编译器会在堆栈内存中创建一个临时对象并将引用值返回给 t2。

如果这是正确的,我该如何表达或解释option1?似乎在堆栈内存中创建了相同的对象,并且计算机为该对象提供了名称“t2”,但我不清楚此选项 1与选项 2有何不同,因为变量和引用的名称有些令人困惑。

此外,交替切换选项,我可以看到在每种情况下对象都是在不同的内存位置创建的。(例如option1的对象是在0x7fff5fbff828中创建的,或者option2是在0x7fff5fbff820中的)

你能解释一下吗

1.变量名(option1)和引用(option2)有什么区别。

2.选项 1 和 2 的工作方式有何不同。

3.为什么在这两种情况下都在不同的内存位置创建对象。

在此先感谢您的帮助!

4

2 回答 2

3
const TestClass t2 = TestClass(100); //option1
const TestClass &t2 = TestClass(100); //option2

选项1:

调用 TestClass 的复制构造函数并传入在“=”右侧创建的临时值。复制省略消除了不必要的对象复制(参见下面的 Piotrs 评论)。

选项 2:

您创建 1 个对象,即临时对象,该对象将绑定到引用。

  1. 变量名(选项1)和引用(选项2)有什么区别。

编辑:我以前不知道这一点,但实际上选项 1 中没有第二次分配(感谢 Piotr)这是由于复制省略,它指的是一种编译器优化技术,可以消除不必要的对象复制。

用你的话来说,“变量名”是一块包含数据的内存。引用就像一个指针,它指向另一个“变量名”,但它必须被初始化,并且永远不会为空。

  1. 选项 1 和 2 中的工作方式有何不同。

正如其他人所说,选项 1 是静态类型,其中选项 2 可以指向派生(来自 TestClass)对象的实例。

  1. 为什么在这两种情况下都在不同的内存位置创建对象。

尽管是“相同的”TestObjects(100),但它们是单独的实例,因此在不同的内存(地址)中

于 2012-11-03T23:30:43.463 回答
1

1)变量名(选项1)和引用(选项2)有什么区别。

名称具有静态类型。引用可以绑定到派生类——我们不知道引用对象的确切类型。

在您的示例中 - 对于选项 2 - 您通过创建对临时对象的 const 引用来延长临时对象的生命周期 - 请参阅http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-最重要的常量/

通常,临时对象只持续到它出现的完整表达式的结尾。但是,C++ 特意指定将临时对象绑定到堆栈上的 const 引用会将临时对象的生命周期延长到引用本身的生命周期,从而避免常见的悬空引用错误。


2)选项 1 和 2 中的工作方式有何不同。

如果您调用虚函数 - 那么对于变量名,您知道将调用哪个函数,对于引用 - 您无法知道比您的示例更复杂的示例。


3)为什么在这两种情况下都在不同的内存位置创建对象。

它们是不同的对象,它们同时存在——那么为什么它们的内存位置应该相同呢?

其他区别是,对于选项 1,您创建了自动变量,对于选项 2,它是临时变量 - 两者都可能使用不同的内存(堆栈与寄存器或仅用于临时的一些保留内存)


考虑更复杂的例子:

class TestClass{
protected:
    int num;
public:
    TestClass(int n):num(n){
        cout<<this<<" : init of : " <<this->num<<endl;
    }
    TestClass(const TestClass& t):num(t.num){
        cout<<this<<" : copyInit of : " <<this->num<<endl;
    }
    virtual void printNum () const { cout << "NUM: " << num << endl; }
};

class TestClassDerived : public TestClass {
public:
    TestClassDerived(int n):TestClass(n){}
    virtual void printNum () const { cout << "DERIVED NUM: " << num << endl; }
};


int main(int argc, const char * argv[]){
    const TestClass t1 = TestClass(100); //option1
    const TestClass &t2 = TestClassDerived(100); //option2
    t1.printNum();
    t2.printNum();
}
于 2012-11-03T23:28:36.107 回答