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

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

(如果不是很明显为什么,你并不孤单......这对我来说也不明显。)

我的问题:

  1. 处理它的“标准”方式是什么?制作一个新变量然后立即将其分配给某个东西对我来说似乎有点奇怪。有没有更好的处理方法?

  2. 你如何训练自己注意这样的混叠问题?你在寻找什么模式?我不知道承认这种情况;当我了解 C 中的关键字时,我才了解了别名restrict,直到现在我才了解问题的真正含义。


编辑:

我很乐意接受答案,但问题的第 (2) 部分似乎没有得到回答。我想知道人们使用什么策略来定位他们编写的代码中的别名错误。

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

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

4

5 回答 5

5

编辑:从技术上讲,如果包含的类型具有无抛出复制构造函数,则标准不要求这是正确的。我不知道有任何实现,这无论如何都不成立,因为它需要产生两个实现,push_back当通用的实现在所有情况下都一样有效。

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

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)[注:这两个参考分别指的是insertondequevector] 本条款中定义的所有容器类型都满足以下附加要求:

— 如果 push_back() 或 push_front() 函数抛出异常,则该函数无效

重要的是,如果在操作中抛出任何异常,容器保持不变,这意味着没有迭代器失效,这反过来意味着原始内存区域保持不变,直到保证没有异常将被抛出(除了双关语,析构函数)。因为通常复制构造函数可以抛出,所以实现必须确保在销毁任何对象之前执行所有副本。

这在 C++0x 中变得更加明显,当对象不是从一个位置复制到另一个位置时,而是. 由于新元素的副本可能会抛出,因此必须在执行任何移动之前执行它,否则您将处于原始容器中的某些对象已失效的情况。

于 2011-06-02T08:29:48.773 回答
4

我想这将是安全的:

std::vector<int> a(1);
a.push_back(1);
a.push_back(int(a[0]));
于 2011-06-02T05:18:28.747 回答
0

push_back(const T& el);实现中检查是否el在数组或其他内部存储中。这是处理此类问题的唯一政治正确方法。

容器应该将其作为不同的容器处理 - 不同的安全规则。

于 2011-06-02T05:20:56.210 回答
0

这对您来说可能不是一个有用的答案,但恕我直言,“正确”的方法是容器类应该正确处理别名,这样调用者就不必担心它。特别是, push_back() (或等效的)应该执行以下操作:

// C++-ish pseudo-code, exception-safety left as an exercise for the reader
void push_back(const T & t)
{
   if (current_size == alloced_size)
   {
      // Oops, our data array is full.  Time to trade it in for a bigger one
      T * newArray = new T[alloced_size*2];
      copy_items(newArray, current_array, current_size);
      newArray[current_size++] = t;
      delete [] current_array;    // delete old array only AFTER all references to t
      current_array = new_array;
      alloced_size *= 2;
   }
   else current_array[current_size++] = t;
}
于 2011-06-03T01:45:14.117 回答
-2

我只是在做这个,所以请不要认为它是福音,但这行得通吗?

a.push_back(1);
a.push_back(&(new int(a[0])));
于 2011-06-02T05:18:38.073 回答