悬空参考。成语 [英] Dangling Reference. Idiom

查看:111
本文介绍了悬空参考。成语的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个返回对elements的引用的方法。在

迭代器中,以及推进迭代器的方法:


class Element {/ * ... * /};


class Iterator {

public:

Element& operator *()const;


Iterator& operator ++();


/ * ... * /

};

现在,我也想要客户的迭代器要知道对运算符*返回的元素的

引用只是临时有效的b $ b。也就是说,迭代器的客户端不应该在下一次调用operator ++之后保持元素引用,因为它将是b / b
。见下文:


Iterator iter(/ * ... * /);

元素& e = * iter;

/ *做一些e * /

++ iter; //此时引用e变为悬空。

我想向客户端传达语义约束。

评论可能就足够了。但是,我想探讨

在代码中表达约束的可能性。


我发现使用和辅助类这样做:


struct WillDangleRef {//辅助类

运算符元素&()const;


private:

WillDangleRef(WillDangleRef const&); //隐藏未实现


元素& element_;


WillDangleRef(元素& e):element_(e){}

};

class Iterator {

public:

WillDangleRef operator *()const; //操作员*现在返回

一个对象,

//只能用于
用于转换为Element&


Iterator& operator ++();


/ * ... * /

};


WillDangleRef临时将是在包含对运算符*的调用的

语句之后被破坏,这给出了一个线索

关于它可以被转换的引用的瞬态特性

进入。这使得客户只能选择使用引用

作为函数的参数,我不太喜欢,因为我觉得
感觉限制太多了:


void doSomethingWithE(Element& e);


Iterator iter(/ * ... * /);

doSomethingWithE(* iter);

++ iter; //此时* iter返回的临时消失了。

你能评论一下吗?还有其他想法吗?


谢谢:


Belebele

解决方案

Belebele写道:


假设我有一个方法返回对elements的引用在

迭代器中,以及推进迭代器的方法:


class Element {/ * ... * /};


class Iterator {

public:

Element& operator *()const;


Iterator& operator ++();


/ * ... * /

};


现在,我也想要迭代器的客户知道

对运算符*返回的元素的引用仅有效暂时为
。也就是说,迭代器的客户端不应该在下一次调用operator ++之后保持元素引用,因为它将是b / b
。见下文:


Iterator iter(/ * ... * /);

元素& e = * iter;

/ *做一些e * /

++ iter; //此时引用e变为悬空。


我想向客户端传达语义约束。

评论可能就足够了。但是,我想探讨

在代码中表达约束的可能性。


我发现使用和辅助类这样做:


struct WillDangleRef {//辅助类

运算符元素&()const;


private:

WillDangleRef(WillDangleRef const&); //隐藏未实现


元素& element_;


WillDangleRef(元素& e):element_(e){}

};


class Iterator {

public:

WillDangleRef operator *()const; //操作员*现在返回

一个对象,

//只能用于
用于转换为Element&


Iterator& operator ++();


/ * ... * /

};


WillDangleRef临时将是在包含对运算符*的调用的

语句之后被破坏,这给出了一个线索

关于它可以被转换的引用的瞬态特性

进入。这使得客户只能选择使用引用

作为函数的参数,我不太喜欢,因为我觉得
感觉限制太多了:


void doSomethingWithE(Element& e);


Iterator iter(/ * ... * /);

doSomethingWithE(* iter);

++ iter; //此时* iter返回的临时消失了。


你能评论一下吗?还有其他想法吗?



A BAD IDEA(tm)。迭代器不应该是

的对象的所有者,它提供访问权限。迭代器应该只提供一种方法来引用某个特定元素_elsewhere_(就像一个容器)。如果迭代器引用的对象

在迭代器增加后没有生存,你就不应该返回一个引用,你可能应该

返回一个对象的副本(即按值返回)。


至于你的WillDangleRef,是什么阻止我做什么


WillDangleRef const& ref = * it; ++ it;


?将''ref''存活下来吗?应该,我引用了它。现在,

在下一个声明之后,无论'ref'允许我访问

仍然无效,不是吗?

V

-

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

我不知道回复最热门的回复,请不要问


A BAD IDEA(tm)。 Iterator不应该是


的对象的所有者,它提供访问权限。



如果我们引导讨论远离我将
命名为我的类Iterator的事实,我更希望如此。我得到的印象是你正在使用关于迭代器的先入为主的想法来形成讨论。我的

的目的是讨论返回临时参考的方法

,根据某些规则会变成悬空。


但是,我想讨论迭代器的概念,但是作为

a的单独主题,一旦我们找到一些与

主题的共同点参考。


关于你的WillDangleRef,什么阻止我做什么


WillDangleRef const& ref = * it; ++ it;


?将''ref''存活下来吗?应该,我引用了它。现在,

在下一个声明之后,无论'ref'允许我访问

仍然无效,不是吗?



我的理解是,一旦创建它的语句完成,临时WillDangleRef对象将被销毁



执行。在这种情况下,该陈述是:


WillDangleRef const& ref = * it;


因此,引用引用将立即变为悬空。使用ref

将导致未定义的行为。我在创建辅助

课程时的观点是向客户(他们了解终身规则

of temporaries)通过调用

在创建WillDangleRef对象的

语句之后,WillDangleRef对象''''运算符元素&''无效。


Victor Bazarov写道:


>

A BAD IDEA(tm)。迭代器不应该是

的对象的所有者,它提供访问权限。



只有一个资格:有时输入迭代器是如何工作的,

这就是为什么你有什么限制的原因使用

输入迭代器。但是应该避免这种事情。

而且,在输入迭代器的情况下,operator *返回一个值,而不是

引用,所以你可以坚持下去无论你使用迭代器做什么,你的结果是什么。


-


- 皮特

Roundhouse Consulting,Ltd。( www.versatilecoding.com

标准C ++库扩展:教程和
参考的作者。 ( www.petebecker.com/tr1book


Suppose that I have a method that returns references to "elements" in
an iterator, and a method to advance the iterator:

class Element { /* ... */ };

class Iterator {
public:
Element& operator*() const;

Iterator& operator++();

/* ... */
};
Now, I also want the clients of the iterator to know that the
reference to element returned by the operator* is only valid
temporarily. That is, clients of the iterator are not supposed to hold
the element reference beyond the next call to operator++, for it will
be dangling. See below:

Iterator iter(/* ... */);
Element &e = *iter;
/* Do something with e */
++iter; // At this point the reference e becomes dangling.
I would like to convey that semantic constraint to the client. A
comment would probably be sufficient. However, I would like to explore
the possibility of expressing the constraint in code.

It occurred to me to use and ancillary class to do so:

struct WillDangleRef { // Ancillary class
operator Element&() const;

private:
WillDangleRef(WillDangleRef const& ); // Hidden. Not Implemented

Element &element_;

WillDangleRef(Element& e): element_(e) {}
};
class Iterator {
public:
WillDangleRef operator*() const; // The operator* now returns
an object that
// can only be
used for conversions into Element&

Iterator& operator++();

/* ... */
};

The WillDangleRef temporary will be destructed right after the
statement that contains the call to the operator*, which gives a clue
as to the transient nature of the reference that it can be converted
into. That leaves clients with the only choice of using the reference
as a parameter to a function, which I do not like very much because I
feel is too restrictive:

void doSomethingWithE(Element& e);

Iterator iter(/* ... */);
doSomethingWithE(*iter);
++iter; // At this point the temporary returned by *iter is gone.
Could you please comment? Any other ideas?

Thanks:

Belebele

解决方案

Belebele wrote:

Suppose that I have a method that returns references to "elements" in
an iterator, and a method to advance the iterator:

class Element { /* ... */ };

class Iterator {
public:
Element& operator*() const;

Iterator& operator++();

/* ... */
};
Now, I also want the clients of the iterator to know that the
reference to element returned by the operator* is only valid
temporarily. That is, clients of the iterator are not supposed to hold
the element reference beyond the next call to operator++, for it will
be dangling. See below:

Iterator iter(/* ... */);
Element &e = *iter;
/* Do something with e */
++iter; // At this point the reference e becomes dangling.
I would like to convey that semantic constraint to the client. A
comment would probably be sufficient. However, I would like to explore
the possibility of expressing the constraint in code.

It occurred to me to use and ancillary class to do so:

struct WillDangleRef { // Ancillary class
operator Element&() const;

private:
WillDangleRef(WillDangleRef const& ); // Hidden. Not Implemented

Element &element_;

WillDangleRef(Element& e): element_(e) {}
};
class Iterator {
public:
WillDangleRef operator*() const; // The operator* now returns
an object that
// can only be
used for conversions into Element&

Iterator& operator++();

/* ... */
};

The WillDangleRef temporary will be destructed right after the
statement that contains the call to the operator*, which gives a clue
as to the transient nature of the reference that it can be converted
into. That leaves clients with the only choice of using the reference
as a parameter to a function, which I do not like very much because I
feel is too restrictive:

void doSomethingWithE(Element& e);

Iterator iter(/* ... */);
doSomethingWithE(*iter);
++iter; // At this point the temporary returned by *iter is gone.
Could you please comment? Any other ideas?

A BAD IDEA(tm). Iterator should not be the owner of the object to
which gives access. Iterator should only provide a way to refer to
some particular element _elsewhere_ (like a container). If the object
to which the iterator refers does not survive after the iterator is
incremented, you shouldn''t return a reference, you should probably
return a copy of the object (i.e. return by value).

As to your "WillDangleRef", what prevents me from doing

WillDangleRef const& ref = *it; ++it;

? Will ''ref'' survive? It should, I bound a reference to it. Now,
right after the next statement whatever ''ref'' allows me to access
is still invalid, isn''t it?

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


A BAD IDEA(tm). Iterator should not be the owner of the object to

which gives access.

I would prefer if we steer the discussion away from the fact that I
named my class Iterator. I get the impression that you are using your
preconceived ideas about iterators to shape the discussion. My
intention is to discuss the method that returns a temporary reference
which will become dangling according to some rule.

However, I would like to discuss that concept of the iterator, but as
a separate topic, once we find some common ground with the topic of
the reference.

As to your "WillDangleRef", what prevents me from doing

WillDangleRef const& ref = *it; ++it;

? Will ''ref'' survive? It should, I bound a reference to it. Now,
right after the next statement whatever ''ref'' allows me to access
is still invalid, isn''t it?

My understanding is that the temporary WillDangleRef object will be
destroyed as soon as the statement where it is created completes
execution. In this case, that statement is:

WillDangleRef const& ref = *it;

Thus, the reference ref will become dangling immediately. Using ref
will cause undefined behavior. My point in creating the auxiliary
class was to convey to clients (who are aware of the life-time rules
of temporaries) that the element reference provided by calling the
WillDangleRef object''s ''operator Element&'' is invalid right after the
statement that created the WillDangleRef object.


Victor Bazarov wrote:

>
A BAD IDEA(tm). Iterator should not be the owner of the object to
which gives access.

Just one qualification: that''s sometimes how input iterators works,
which is why there are so many restrictions on what you can do with an
input iterator. But that sort of thing should definitely be avoided.
And, in the case of input iterators, operator* returns a value, not a
reference, so you can hang on to its result regardless of what you
subsequently do with the iterator.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)


这篇关于悬空参考。成语的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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