什么是“右”方法,以避免在C ++中的别名(例如,当添加一个容器的元素自身)? [英] What is the "right" way to avoid Aliasing (e.g. when adding an element of a container to itself) in C++?

查看:148
本文介绍了什么是“右”方法,以避免在C ++中的别名(例如,当添加一个容器的元素自身)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  std :: vector< int>一个; 
a.push_back(1);
a.push_back(a [0]);

刚刚学到了上面的代码可能是非常危险的。



(如果它不明显为什么, )



我的问题:




  1. 什么是标准的处理方式?创建一个新的变量,然后将其立即分配到一些事情后来似乎有点怪我。是否有更好的处理方式?


  2. 如何训练自己以注意类似这样的别名问题?你寻找什么样的模式?我不知道这种情况;当我在C中了解到 restrict 关键字时,我只学到了别名。现在我才明白这是什么问题。







编辑:



接受答案,但似乎似乎问题的(2)部分已被回答。我想知道人们在他们编写的代码中使用什么策略来定位别名错误。



到目前为止,我提出的一个策略是避免传入同一个值在两个参数。 (在这种情况下,一个参数是隐式的,一个是显式的。)



还有其他容易注意的事情吗?

解决方案

EDIT :从技术上讲,如果包含的类型有一个无throw拷贝构造函数,标准不强制要求这是正确的。我不知道任何实现,这并不持有,因为它将需要生成 push_back 的两个实现,当通用的在所有情况下是一样高效。 p>

别名是一个问题,但不是在这种特殊情况下。代码:

  assert(v.size()> 0); 
v.push_back(v [0]);

通过异常保证(C ++ 03)保证是正确的一个真正好的理由不实现自己的容器,你可能不会得到它们正确)。特别是§23.1[lib.container.requirements] / 10 dictattes:


除非另有规定(见23.2.1.3和23.2.4.3) [注意:这两个引用引用 insert 在 deque code>分别]此子句中定义的所有容器类型满足以下附加要求:



- 如果push_back或者push_front()函数,该函数具有无效果


em>任何异常被抛出的操作中,容器是未修改,这意味着没有迭代器被无效,这反过来意味着原始的内存区域保持不变直到它保证没有异常(使用例外 pun意图,析构函数)。因为一般来说,拷贝构造函数可以抛出,实现必须确保在销毁任何对象之前执行所有副本。



++ 0x,当对象没有从一个位置复制到另一个位置,而是移动 。因为新元素的副本可能会抛出,所以必须在执行任何移动之前执行 ,否则,您将处于原始容器中的某些对象已经无效。


std::vector<int> a;
a.push_back(1);
a.push_back(a[0]);

I just learned that the code above can be very dangerous.

(If it's not obvious why, you're not alone... it wasn't obvious to me either.)

My questions:

  1. What is the "standard" way of dealing with it? Making a new variable and then assigning it immediately to something afterward seems a bit weird to me. Is there a better way of dealing with it?

  2. How do you train yourself to watch out for aliasing issues like this? What pattern(s) do you look for? I have no idea to recognize this situation; I only learned about aliasing when I learned about the restrict keyword in C, and only now do I understand what the issue really is.


Edit:

I'd love to accept an answer, but it doesn't seem like part (2) of the question has been answered. I'm wondering what strategies people use to locate aliasing mistakes in code they have written.

One strategy I've come up with so far is to avoid passing in the same value for in two parameters. (In this case, one parameter is implicit and one explicit.)

Are there any other easy things to notice and watch out for?

解决方案

EDIT: Technically, the standard does not mandate that this is correct if the contained type has a no-throw copy constructor. I don't know any implementation where this does not hold anyway, as it would require producing two implementations of push_back when the generic one is just as efficient in all cases.

Aliasing is a problem in general, but not in this particular case. The code:

assert( v.size() > 0 );
v.push_back( v[0] );

Is guaranteed to be correct by the standard (C++03) through the exception guarantees (which are a really good reason not to implement your own containers, you will probably not get them right). In particular §23.1 [lib.container.requirements] / 10 dictattes:

Unless otherwise specified (see 23.2.1.3 and 23.2.4.3) [NOTE: both those references refer to insert on deque and vector respectively] all container types defined in this clause meet the following additional requirements:

— if an exception is thrown by a push_back() or push_front() function, that function has no effects.

Where the important bit is that if any exception is thrown in the operation, the container is left untouched, and that means that no iterator gets invalidated, which in turns means that the original region of memory is left untouched until it is guaranteed that no exceptions will be thrown (with the exception pun intended, of destructors). Because in general copy constructors can throw, the implementation must ensure that all copies are performed before destroying any object.

This becomes more evident in C++0x, when objects are not copied from one location to another, but rather moved. Because the copy of the new element might throw, it has to be performed before any of the moves are executed, or else you would be left in a situation where some of the objects in the original container have been invalidated.

这篇关于什么是“右”方法,以避免在C ++中的别名(例如,当添加一个容器的元素自身)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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