是否“T const& t = C()。a;延长“a”的寿命。 [英] Does "T const&t = C().a;" lengthen the lifetime of "a"?

查看:125
本文介绍了是否“T const& t = C()。a;延长“a”的寿命。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下场景,解释为C ++ 0x代码:

  struct B {}; 
struct A {B b; };
int main(){
B const& b = A()。
/ *是对象还活着吗? * /
}

Clang和GCC :Clang延长了生命。 GCC将 B 移动到一个新的临时对象,然后将引用绑定到该新的临时对象。



我找不到任何行为可以从标准的词汇衍生出来。表达式 A()。b 不是临时的(见5.2.5)。




  • 希望的行为(委员会的意图)

  • 从FDIS派生的行为



谢谢!

解决方案

在N3126 = 10-0116的12.2第5段中,它表示:


其中临时是
在与
的结束不同的点被销毁的全表达式]是当引用
绑定到临时时。引用绑定到的临时

临时(即引用
绑定到的子对象的完整对象
)在$ b $的生命周期内仍然存在b引用除了...


,然后遵循四个特殊情况的列表(ctor-inizializers,参考参数,返回值,new因此(在这个版本中)我认为clang是正确的,因为你绑定了一个临时子对象的引用。



EDIT



考虑到对象的基础子对象,这也似乎是唯一合理的行为。替代方法意味着在切片:

  Derived foo(); 
...
void bar()
{
Base& x = foo(); //与foo()没什么区别。
...
}

g ++区分成员子对象和基础子对象,但我不明白在标准中进行这种区分。下面是我使用的测试程序,它清楚可见的两种情况的不同处理...( B 是Base, D 是Derived并且 C 是由)组成。

  #include< iostream> 

struct B
{
B()
{std :: cout< B {<这个<< } :: B()\\\
; }

B(const B& x)
{std :: cout< B {<这个<< } :: B(const B&<<& x<<)\\\
; }

virtual〜B()
{std :: cout< B {<这个<< } ::〜B()\\\
; }

virtual void doit()const
{std :: cout< B {<这个<< } :: doit()\\\
; }
};

struct D:B
{
D()
{std :: cout< D {<<这个<< } :: D()\\\
; }

D(const D& x)
{std :: cout< D {<<这个<< } :: D(const D&<<& x<<)\\\
; }

virtual〜D()
{std :: cout< D {<<这个<< } ::〜D()\\\
; }

virtual void doit()const
{std :: cout< D {<<这个<< } :: doit()\\\
; }
};

struct C
{
B b;

C()
{std :: cout< C {<<这个<< } :: C()\\\
; }

C(const C& x)
{std :: cout< C {<<这个<< } :: C(const C&<<& x<)\\\
; }

〜C()
{std :: cout< C {<<这个<< } ::〜C()\\\
; }
};

D foo()
{
return D();
}

void bar()
{
std :: cout< 之前调用foo()\\\
;
const B& b = foo();
std :: cout<< 调用foo()\\\
;
b.doit();
std :: cout<< 调用b.doit()\\\
;

const B& b2 = C()。
std :: cout<< 绑定到.b \\\
之后;
b2.doit();
std :: cout<< 调用b2.doit()\\\
;
}

int main()
{
std :: cout< 之前调用bar()\\\
;
bar();
std :: cout<< 调用bar()\\\
;
return 0;
}

我用g ++得到的输出(Ubuntu / Linaro 4.4.4-14ubuntu5) 4.4.5是

 在调用bar()之前
在调用foo()之前
B {0xbf9f86ec} :: B()
D {0xbf9f86ec} :: D()
调用foo()后
D {0xbf9f86ec} :: doit()
调用b.doit )
B {0xbf9f86e8} :: B()
C {0xbf9f86e8} :: C()
B {0xbf9f86e4} :: B(const B& 0xbf9f86e8)
C { 0xbf9f86e8} ::〜C()
B {0xbf9f86e8} ::〜B()
绑定到.b
B {0xbf9f86e4} :: doit()
调用b2.doit()
B {0xbf9f86e4} ::〜B()
D {0xbf9f86ec} ::〜D()
B {0xbf9f86ec} b调用bar()后

在我看来,这是一个在g ++中的错误或c ++标准强制要求这是真正的预期行为还是可能的可接受的行为(但我必须告诉我,我没有真正考虑它,这只是一种感觉,这种差异的东西是错误的)。


The following scenario is given, to be interpreted as C++0x code:

struct B { }; 
struct A { B b; }; 
int main() { 
  B const& b = A().b; 
  /* is the object still alive here? */
}

Clang and GCC (trunk version as of 2011/02) behave differently: Clang lengthens the lifetime. GCC moves B to a new temporary object, and then binds the reference to that new temporary.

I cannot find either behavior can be derived from the words of the Standard. The expression A().b is not a temporary (see 5.2.5). Can anyone please explain the following to me?

  • Desired behavior (the intent of the committee)
  • The behavior as you derive it from the FDIS

Thanks!

解决方案

In 12.2 paragraph 5 of N3126=10-0116 it's said that:

The second context [ in which temporaries are destroyed at a different point than the end of the full-expression ] is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except ...

and then follows a list of four special cases (ctor-inizializers, reference parameters, returned value, new initializer).

So (in this version) seems to me that clang is correct because you're binding the reference to a subobject of a temporary.

EDIT

Thinking to the base sub-object of an object this also seems to be the only reasonable behavior. The alternative would mean doing a slicing in:

Derived foo();
...
void bar()
{
    Base& x = foo(); // not very different from foo().b;
    ...
}

Actually after making a little experiment seems indeed that g++ differentiates between a member sub-object and a base sub-object, but I don't understand where this differentiation is made in the standard. The following is the test program I used and where it's clearly visible the different handling of the two cases... (B is Base, D is Derived and C is composed).

#include <iostream>

struct B
{
    B()
    { std::cout << "B{" << this << "}::B()\n"; }

    B(const B& x)
    { std::cout << "B{" << this << "}::B(const B& " << &x << ")\n"; }

    virtual ~B()
    { std::cout << "B{" << this << "}::~B()\n"; }

    virtual void doit() const
    { std::cout << "B{" << this << "}::doit()\n"; }
};

struct D : B
{
    D()
    { std::cout << "D{" << this << "}::D()\n"; }

    D(const D& x)
    { std::cout << "D{" << this << "}::D(const D& " << &x << ")\n"; }

    virtual ~D()
    { std::cout << "D{" << this << "}::~D()\n"; }

    virtual void doit() const
    { std::cout << "D{" << this << "}::doit()\n"; }
};

struct C
{
    B b;

    C()
    { std::cout << "C{" << this << "}::C()\n"; }

    C(const C& x)
    { std::cout << "C{" << this << "}::C(const C& " << &x << ")\n"; }

    ~C()
    { std::cout << "C{" << this << "}::~C()\n"; }
};

D foo()
{
    return D();
}

void bar()
{
    std::cout << "Before calling foo()\n";
    const B& b = foo();
    std::cout << "After calling foo()\n";
    b.doit();
    std::cout << "After calling b.doit()\n";

    const B& b2 = C().b;
    std::cout << "After binding to .b\n";
    b2.doit();
    std::cout << "After calling b2.doit()\n";
}

int main()
{
    std::cout << "Before calling bar()\n";
    bar();
    std::cout << "After calling bar()\n";
    return 0;
}

The output I get with g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5 is

Before calling bar()
Before calling foo()
B{0xbf9f86ec}::B()
D{0xbf9f86ec}::D()
After calling foo()
D{0xbf9f86ec}::doit()
After calling b.doit()
B{0xbf9f86e8}::B()
C{0xbf9f86e8}::C()
B{0xbf9f86e4}::B(const B& 0xbf9f86e8)
C{0xbf9f86e8}::~C()
B{0xbf9f86e8}::~B()
After binding to .b
B{0xbf9f86e4}::doit()
After calling b2.doit()
B{0xbf9f86e4}::~B()
D{0xbf9f86ec}::~D()
B{0xbf9f86ec}::~B()
After calling bar()

In my opinion this is either a bug in g++ or a bug in what the c++ standard mandates if this is really the expected behavior or a possible acceptable behavior (but I must tell that I didn't really think about it a lot, this is just a feeling that something is wrong with this differentiation).

这篇关于是否“T const&amp; t = C()。a;延长“a”的寿命。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆