【问题标题】:Difference between variable reference and name变量引用和名称之间的区别
【发布时间】:2012-11-03 23:18:15
【问题描述】:

我正在研究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”,但我不清楚这个 option1option2 有何不同strong> 因为变量和引用的名称有些混乱。

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

请解释一下

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

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

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

提前感谢您的帮助!

【问题讨论】:

  • 我会尝试回答这个问题,但您的第三个问题让我感到困惑......代码是否编译?
  • @LewsTherin 如果重命名第一个选项,它会编译。
  • 请注意,在TestClass t = *(new TestClass(55)); 中您不再可以delete 分配的内存。
  • @Lews Therin 哦,我没有构建包含这两行的代码。我分别测试了每个选项,注释掉另一个。但问题是每次我测试选项 1 时,对象都会在内存点 A 中创建,并使用选项 2 在内存点 B 中创建。
  • @Jesse 非常感谢!我正在测试复制初始化如何与这一行一起工作。

标签: c++ variables pointers reference


【解决方案1】:
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),但它们是单独的实例,因此在不同的内存(地址)中

【讨论】:

  • 您能演示一下如何更改选项 1 中的对象吗?在我看来,它看起来是 const
  • 有任何证据表明选项 1 中发生了额外分配吗?在 ideone 上查看我的示例:ideone.com/VJiVLf。没有额外的分配...
  • @PiotrNycz 有趣的是,这不是我所期望的。是否因为 const 对象而优化?
  • @Caribou 非常感谢 Caribou。它帮助很大!那么在实践中,btw/变量名和引用的唯一区别是它们可以容纳什么?
  • 有趣的是,我会在这个问题之前回答“是”,但现在我发现自己在质疑我认为是真的一切。用你的话来说,“变量名”是一块包含数据的内存。引用就像一个指针,它指向另一个“变量名”,但它必须被初始化,并且永远不会为空
【解决方案2】:

1) 变量名(option1) 和 参考(选项2)。

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

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

通常,临时对象只持续到完整的结束 它出现的表达式。但是,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();
}

【讨论】:

  • 感谢您的解释。我可以问你更多细节吗? a1) 在答案 1 中,您能否详细解释一下静态类型?当我像“const TestClass t2 = TestClassDerived(100);”这样更改您的示例代码时,我可以看到复制初始化发生并且超类类型的新对象被分配给 t2。那么,“变量名作为静态类型”是否意味着它将始终以自己的类型表示对象,通过将分配的派生对象的副本作为其声明的类型? --待续
  • @noclew - for 1:您从派生对象的分配称为切片。 t2 是在左侧声明的类型 - 它只复制 TestClassDerived(100) 的基本部分 - 通常你应该避免它:更多细节:stackoverflow.com/questions/274626/…
  • @noclew - 2:是的,你完全理解。考虑一下:void foo(TestClass&amp; t); TestClassDerived d(100); foo(d); - 当您编写 foo 的实现时 - 您不知道其参数的最派生类型。
  • @noclew 好点。 &amp; 不仅是表示对象的方式。 TestClass(100) 是在所谓的临时内存中创建的。它可以是一些 RAM 或寄存器——任何东西——编译器决定它在哪里。当内部函数 TestClass t(100); 创建自动变量时 - 它在我知道的每个编译器的堆栈中。所以有两种截然不同的记忆——所以不同。此代码:const TestClass&amp; t = TestClass(100); - 只是将临时 TestClass(100) 的生命周期延长到 const 引用的生命周期。
  • @noclew - 也许非 const 引用不会延长临时对象的生命周期。可能有很多事情要记住 - 我正在考虑将引用作为指针和“变量名”之间的东西......您可能会发现这很有帮助:stackoverflow.com/questions/57483/…
猜你喜欢
  • 1970-01-01
  • 2015-10-20
  • 2013-03-21
  • 2014-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-22
相关资源
最近更新 更多