C ++引用和临时对象

时间:2019-07-12 15:14:10

标签: c++ reference

我目前正在使用特定的嵌入式系统(使用C ++),该系统中没有太多内存。因此,使用new / delete是不可能的。我确实已经设置了一些内存管理系统,但是,我正在探索其他方法来解决某些问题(与内存管理不完全相关,但这在这里并不重要)。在搜索过程中,出现了一个相当简单的问题,但我仍然不确定100%的答案,因此,我希望听到专家对此的答复。

最后,我的问题实际上是关于C ++中的引用以及瞬态对象的确切功能。

class Obj
{
    // id is automatically set, starting from 1, step by 1
    public: const int id = ...;

        // other unrelated stuff in the class
};

class Test
{
    public: Obj& obj;
    public: Test(Obj&& o) : obj(o) { }
};

void test()
{
    Obj o1; // id is 1
    Obj o2; // id is 2

    Test t = Obj(); // [*] id of this transient obj is 3

    cout << t.obj.id << endl; // prints 3, as expected?
}

我知道右值引用是左值(因为它们是命名对象,而命名对象始终是左值),因此Test类还可以,并且没有错误(编译错误)。但是,据我所知,瞬时对象Obj()(标有*)应在;之后销毁。在同一行上,因此如果我是正确的话,那么之后的测试对象“ t”应该对被破坏的对象具有无效的引用。而且3打印实际上是意料之外的行为,但是偶然的是它仍然有3写在我的内存位置中,我在打印时正在访问它。这是实际发生的事情,还是我缺少其他需要了解/知道的东西?是否没有某种机制可以检测到这种情况并延长/延长对象的寿命,直到引用它的对象也被销毁(在本示例中,延长Obj()的寿命直到函数test( ),当“ t”被销毁时)?

2 个答案:

答案 0 :(得分:1)

您称为“临时对象”的标准名称是“临时对象”。

  

但是,据我所知,应该在;之后销毁瞬时对象Obj()(标记为*)。在同一行上,因此如果我是正确的话,那么之后的测试对象“ t”应该对被破坏的对象具有无效的引用。而且3打印实际上是意外行为

您是正确的。该引用无效。该行为是不确定的。

临时生存期一直延续到完整表达式的结尾。除非绑定到参考并且参考的寿命更长,在这种情况下,生存期会延长到参考的寿命。

在这种情况下,临时对象绑定到作为构造函数参数的引用,该引用的生存期不超过调用构造函数的完整表达式的时间。


  

没有某种机制可以检测到这种情况并延长/延长对象的寿命,直到引用它的对象也被销毁(在本示例中,将Obj()的寿命延长到对象的结束)。函数test(),当't'被销毁时)?

是的!该机制是班级成员。与与对象无关的临时对象不同,成员对象的生存时间至少与包含它们的对象一样长。

struct Test
{
    Obj obj;
};

Test t{};

答案 1 :(得分:1)

让我稍微修改一下您的示例。我删除了const,并向Obj添加了一个析构函数。如您所见,对象已被破坏。对于您而言,没有析构函数,id不会被覆盖,但是您不能依靠它。

class Obj {
private:
    static int next;
public:
    int id;
    Obj() {
        id = next;
        ++next;
    }
    ~Obj() {
        id = 42;
    }
};
int Obj::next = 1;

class Test {
public:
    Obj& obj;
    Test(Obj&& o) : obj(o) { }
};

void test() {
    Obj o1; // id is 1
    Obj o2; // id is 2
    Test t = Obj(); // id is 3
    cout << t.obj.id << endl; // prints 42
}

[编辑]

最好将复制构造函数添加到Obj并修改Test以存储给定const引用对象的副本。

class Obj {
private:
    static int next;
public:
    int id;
    Obj() {
        id = next;
        ++next;
    }
    Obj(const Obj& x) {
        id = next;
        ++next;
    }
    ~Obj() {
        id = 42;
    }
};
int Obj::next = 1;

class Test {
public:
    Obj obj;
    Test(const Obj& o) : obj(o) {}
};

void test() {
    Obj o1; // id is 1
    Obj o2; // id is 2
    Test t = Obj(); // id is 3
    cout << t.obj.id << endl; // prints 4
}