终身延伸误解 [英] Lifetime extension misconception

查看:80
本文介绍了终身延伸误解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



有一个常见的误解,(我自己也曾在一个点上持有),

一个const引用可以延长临时的生命周期 ;。示例

如下所示:


代码段(1)

---------- -


#include< string>

使用std :: string;


#include< iostream> ;

使用std :: cout;


string Func()

{

return" ;你好;

}


int main()

{

string const& str = Func();


cout<< str<< ''\\ n';;

}


在上面的代码片段中,没有临时的生命周期延长。如果这样的事情是真的,那么下面的代码就完全可以了:


代码片段(2):

- -----------


#include< string>

使用std :: string;


string Func()

{

return" Hello" ;;

}


int main()

{

string const& cstr = Func();


string& str = const_cast< string&>(cstr);


str =" World";

}

但是,唉, Snippet(2)表现出未定义的行为,因为引用

不引用函数返回的原始非const对象




Snippet(1)中的代码与以下原理完全相同

代码片段:


代码段(3) ):

------------


int main()

{

int const& r = 5;

}


在Snippet(1)和Snippet(3)中,const引用保持有效NOT

因为临时生命已延长,但因为引用

用R值初始化。 C ++标准定义了这个过程:


如果初始化表达式是一个右值,T2是一个类类型,而?cv1

T1?与?cv2 T2参考兼容?以下方式将参考绑定在

之一(选项是实现定义的):

?引用绑定到rvalue(参见3.10)

或该对象中的子对象所代表的对象。

?暂时的类型?cv1 T2?创建[sic],并将构造函数称为

,将整个右值对象复制到临时对象中。临时或临时内的子对象将引用绑定为



这解释了为什么以下代码片段无法编译和反驳

通过将const引用绑定到

来延长临时的生命周期。


Snippet(4):< br $>
------------


class MyClass {

private:

MyClass(MyClass const&); / *不能复制 - 构建! * /


public:

MyClass(){}

};


int main()

{

MyClass const& r = MyClass();

}


-


Frederick Gotham

解决方案

Frederick Gotham写道:


有一个常见的误解,(我自己也在一个

点),一个const引用可以延长
临时"。给出如下例子:


小片(1)

-----------

#include< string>

使用std :: string;


#include< iostream>

使用std :: cout;


string Func()

{

return" Hello" ;;

}


int main()

{

string const& str = Func();


cout<< str<< ''\\ n';;

}


在上面的代码片段中,没有临时的延长了生命周期。

如果这样的事情是真的,那么下面的代码将是完美的

好​​的:


片段(2):

------------


#include< string>

使用std :: string;


string Func()

{

return" Hello";

}


int main()

{

string const& cstr = Func();


string & str = const_cast< string&>(cstr);


str =" World";

}


但是,Snippet(2)表现出未定义的行为,因为

引用不引用原始的非const对象,它是由值返回的

函数。


代码片段(1)中的代码与

完全相同的原理如下代码片段:


片段(3):

------------


int main()

{

int const& r = 5;

}


In Snippet(1)并且在Snippet(3)中,const引用仍然有效

不是因为临时生命周期延长了,而是因为

引用初始化为R值。 C ++标准定义了

这个过程:


如果初始化表达式是一个rvalue,T2是一个类类型,并且

?cv1 T1?与?cv2 T2参考兼容?引用是以下列方式之一绑定的
(选项是

实现定义):

?引用绑定到由右值表示的对象(参见

3.10)或该对象中的子对象。

?暂时的类型?cv1 T2?创建[sic],并调用构造函数
将整个右值对象复制到临时对象中。

引用绑定到

临时内的临时或子对象。


这解释了为什么以下代码片段无法编译,并且

通过绑定

const引用来反驳临时的生命周期。


代码段(4):

------------


class MyClass {

私人:

MyClass(MyClass const&); / *不能复制 - 构建! * /


public:

MyClass(){}

};


int main()

{

MyClass const& r = MyClass();

}



这是另一个有趣的例子:


char const * hello(){return" Hello" ;; }


#include< string>

#include< iostream>


int main(){

std :: string const& str = hello();

std :: cout<< str<< std :: endl;

}


临时不会从任何地方返回,它是作为结果创建的

参考文献的初始化。没有生命周期扩展,

只有绑定引用的临时生命周期。如果

它是原始的临时,你可以将其视为扩展。它的生命周期是
,但是你用私人拷贝构造函数确定的点b / b
它不一定是原来的临时版。它可以像另一个*临时的,由原始的复制构造。或者来自

其他东西,比如我的例子。


就像在任何其他情况下按值返回一样,copy-c-tor

必须是合法的代码,即使没有复制也是如此。


V

-

请在通过电子邮件回复时删除资金''A'

我没有回复最热门的回复,请不要问


Frederick Gotham写道:


有一个常见的误解,(我自己也曾在一个地方举行),

const引用可以延长临时生命周期。



这不是误解。


#include< string>

使用std :: string;


#include< iostream>

使用std :: cout;


string Func()

{

return" Hello" ;;

}


int main()

{

string const& str = Func();


cout<< str<< ''\\ n';;

}


在上面的代码片段中,没有临时的生命周期延长。



Func()的返回值是临时的。它的生命周期延长了

被绑定到''str''。


如果没有延长它的寿命,那么cout<< ; str将是

引用一个不再存在的对象。


如果这样的事情是真的,那么下面的代码就完全可以了:


小部件(2):

------------


#include< string>

使用std :: string;


string Func()

{

返回你好;

}


int main()

{

string const& cstr = Func();


string& str = const_cast< string&>(cstr);


str =" World";

}



是的,该代码没问题。


但唉,Snippet(2)表现出未定义的行为,



不,它没有。


因为引用没有引用原始的非const对象

这是由值返回的来自该功能。



引用是指函数的返回值,而不是按值返回的

原始对象。正如您所说。 br />


Snippet(1)中的代码与以下原理完全相同

代码片段:


小部件(3):

------------


int main()

{

int const& r = 5;

}


在Snippet(1)和Snippet中( 3),const引用仍然有效NOT

因为临时生命周期延长了,



该代码创建一个临时int,初始化它到5,然后

绑定''r''。临时的生命周期扩展到''r''的范围。


但因为引用是用R-初始化的价值。

C ++标准定义了这个过程:


- 类型为cv1 T2的临时类型。创建[sic],并将构造函数称为

,将整个右值对象复制到临时对象中。引用绑定到临时或临时内的子对象



是的,这就是发生的事情。临时类型为int的类型已创建,

及其复制构造函数用于初始化它为5.

参考

然后绑定到临时,并且临时'生命周期是

扩展。


我把复制构造函数在引号中,因为英特尔不是真的有副本

构造函数。字符串示例更直接。


这解释了为什么以下代码片段无法编译

并反驳临时的生命周期通过绑定来扩展

a const引用它。



没有这样的事情。


>

Snippet(4):

----------- -


class MyClass {

private:

MyClass(MyClass const&); / *不能复制 - 构建! * /


public:

MyClass(){}

};


int main()

{

MyClass const& r = MyClass();

}



这无法编译,因为标准明确表示在使用

a临时初始化引用时需要一个

复制构造函数。实际上你早先引用了标准的这一部分。


在这整个帖子中,我认为你混淆了返回的对象是

,返回值。返回值(临时的)

存在于调用函数的范围内,并且是从被返回的对象复制构造的

(存在于范围内)

称为函数)。


通常,返回值在full-

表达式的末尾被销毁,因为它是暂时的。但是当它被绑定到

a const引用时,它就不会被破坏。


老狼张贴:
< blockquote class =post_quotes>


>但是唉,Snippet(2)表现出未定义的行为,



没有它那并不。



阅读有关将const引用绑定到R值的规则:


- 临时类型为cv1 T2"创建[sic],并将构造函数称为

,将整个右值对象复制到临时对象中。临时或临时内的子对象将参考绑定为




记下上段中的第五个单词 - " ; cv1"。


代码片段(2)调用未定义的行为。


-


Frederick Gotham



There is a common misconception, (one which I myself also held at one point),
that a const reference can "extend the lifetime of a temporary". Examples
such as the following are given:

Snippet (1)
-----------

#include <string>
using std::string;

#include <iostream>
using std::cout;

string Func()
{
return "Hello";
}

int main()
{
string const &str = Func();

cout << str << ''\n'';
}

In the above snippet, no temporary "has had its lifetime extended". If such a
thing were true, then the following code would be perfectly OK:

Snippet (2):
------------

#include <string>
using std::string;

string Func()
{
return "Hello";
}

int main()
{
string const &cstr = Func();

string &str = const_cast<string&>(cstr);

str = "World";
}
But alas, Snippet (2) exhibits undefined behaviour, because the reference
does not refer to the original non-const object which was returned by value
from the function.

The code in Snippet (1) works on exactly the same principle as the following
code snippet:

Snippet (3):
------------

int main()
{
int const &r = 5;
}

In Snippet (1) and in Snippet (3), the const reference remains valid NOT
because a temporary has had its liftime extended, but because the reference
was initialised with an R-value. The C++ Standard defines this process:

If the initializer expression is an rvalue, with T2 a class type, and ?cv1
T1? is reference-compatible with ?cv2 T2,? the reference is bound in one of
the following ways (the choice is implementation-defined):
? The reference is bound to the object represented by the rvalue (see 3.10)
or to a sub-object within that object.
? A temporary of type ?cv1 T2? [sic] is created, and a constructor is called
to copy the entire rvalue object into the temporary. The reference is bound
to the temporary or to a sub-object within the temporary.

This explains why the following code snippet fails to compile, and disproves
that the lifetime of a temporary is extended by binding a const reference to
it.

Snippet (4):
------------

class MyClass {
private:
MyClass(MyClass const &); /* Can''t copy-construct! */

public:
MyClass() {}
};

int main()
{
MyClass const &r = MyClass();
}

--

Frederick Gotham

解决方案

Frederick Gotham wrote:

There is a common misconception, (one which I myself also held at one
point), that a const reference can "extend the lifetime of a
temporary". Examples such as the following are given:

Snippet (1)
-----------

#include <string>
using std::string;

#include <iostream>
using std::cout;

string Func()
{
return "Hello";
}

int main()
{
string const &str = Func();

cout << str << ''\n'';
}

In the above snippet, no temporary "has had its lifetime extended".
If such a thing were true, then the following code would be perfectly
OK:

Snippet (2):
------------

#include <string>
using std::string;

string Func()
{
return "Hello";
}

int main()
{
string const &cstr = Func();

string &str = const_cast<string&>(cstr);

str = "World";
}
But alas, Snippet (2) exhibits undefined behaviour, because the
reference does not refer to the original non-const object which was
returned by value from the function.

The code in Snippet (1) works on exactly the same principle as the
following code snippet:

Snippet (3):
------------

int main()
{
int const &r = 5;
}

In Snippet (1) and in Snippet (3), the const reference remains valid
NOT because a temporary has had its liftime extended, but because the
reference was initialised with an R-value. The C++ Standard defines
this process:

If the initializer expression is an rvalue, with T2 a class type, and
?cv1 T1? is reference-compatible with ?cv2 T2,? the reference is
bound in one of the following ways (the choice is
implementation-defined):
? The reference is bound to the object represented by the rvalue (see
3.10) or to a sub-object within that object.
? A temporary of type ?cv1 T2? [sic] is created, and a constructor is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object within the
temporary.

This explains why the following code snippet fails to compile, and
disproves that the lifetime of a temporary is extended by binding a
const reference to it.

Snippet (4):
------------

class MyClass {
private:
MyClass(MyClass const &); /* Can''t copy-construct! */

public:
MyClass() {}
};

int main()
{
MyClass const &r = MyClass();
}

Here is another interesting example:

char const* hello() { return "Hello"; }

#include <string>
#include <iostream>

int main() {
std::string const& str = hello();
std::cout << str << std::endl;
}

The temporary is not returned from anywhere, it''s created as the result
of the initialisation of the reference. There is no lifetime "extention",
only the lifetime of the temporary to which the reference is bound. If
it is the original temporary, you can think of it as "extention" of its
lifetime, but the point you made with your private copy-c-tor constructor
is that it doesn''t have to be the original temporary. It could just as
well be *another* temporary, copy-constructed from the "original" or from
something else, like in my example.

Just like in any other situation with returning by value, the copy-c-tor
has to be available for the code to be legal, even if copying is not done.

V
--
Please remove capital ''A''s when replying by e-mail
I do not respond to top-posted replies, please don''t ask


Frederick Gotham wrote:

There is a common misconception, (one which I myself also held at one point),
that a const reference can "extend the lifetime of a temporary".

That is not a misconception.

#include <string>
using std::string;

#include <iostream>
using std::cout;

string Func()
{
return "Hello";
}

int main()
{
string const &str = Func();

cout << str << ''\n'';
}

In the above snippet, no temporary "has had its lifetime extended".

The return value of Func() is a temporary. It has its lifetime extended
by being bound to ''str''.

If it did not have its lifetime extended, then the cout << str would be
referencing an object that no longer existed.

If such a thing were true, then the following code would be perfectly OK:

Snippet (2):
------------

#include <string>
using std::string;

string Func()
{
return "Hello";
}

int main()
{
string const &cstr = Func();

string &str = const_cast<string&>(cstr);

str = "World";
}

yes, that code is OK.

But alas, Snippet (2) exhibits undefined behaviour,

No it doesn''t.

because the reference does not refer to the original non-const object
which was returned by value from the function.

The reference refers to the return value of the function, not the
original object that was returned by value, as you say.

The code in Snippet (1) works on exactly the same principle as the following
code snippet:

Snippet (3):
------------

int main()
{
int const &r = 5;
}

In Snippet (1) and in Snippet (3), the const reference remains valid NOT
because a temporary has had its liftime extended,

That code creates a temporary int , initializes it to 5, and then
binds ''r'' to it. The temporary has its lifetime extended to the
scope of ''r''.

but because the reference was initialised with an R-value.
The C++ Standard defines this process:

- A temporary of type "cv1 T2" [sic] is created, and a constructor is called
to copy the entire rvalue object into the temporary. The reference is bound
to the temporary or to a sub-object within the temporary.

Yes, that is what happened. A temporary of type "int" was created,
and its "copy constructor" was used to initialize it with 5. The
reference
is then bound to the temporary, and that temporary''s lifetime is
extended.

I put "copy constructor" in quotes because ints don''t really have copy
constructors. The string example is more straight forward.

This explains why the following code snippet fails to compile
and disproves that the lifetime of a temporary is extended by binding
a const reference to it.

It does no such thing.

>
Snippet (4):
------------

class MyClass {
private:
MyClass(MyClass const &); /* Can''t copy-construct! */

public:
MyClass() {}
};

int main()
{
MyClass const &r = MyClass();
}

This fails to compile because the standard explicitly says that a
copy constructor is needed when initializing a reference with
a temporary. In fact you quoted that section of the standard earlier.

In this whole thread, I think you are confusing the object being
returned, with the return value. The return value (a temporary)
exists in the scope of the calling function, and is copy-constructed
from the object being returned (which exists in the scope of the
called function).

Normally the return value is destroyed at the end of the full-
expression, since it is a temporary. But when it is bound to
a const reference, it is not destroyed.


Old Wolf posted:

>But alas, Snippet (2) exhibits undefined behaviour,


No it doesn''t.


Read the rules about binding a const reference to an R-value:

- A temporary of type "cv1 T2" [sic] is created, and a constructor is called
to copy the entire rvalue object into the temporary. The reference is bound
to the temporary or to a sub-object within the temporary.

Take note of the fifth word in the above paragraph -- "cv1".

Code Snippet (2) invokes Undefined Behaviour.

--

Frederick Gotham


这篇关于终身延伸误解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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