8

这不是关于为什么要编写这样的代码的问题,而是关于方法如何相对于它所绑定的对象执行的问题。

如果我有这样的结构:

struct F
{
    // some member variables
    void doSomething(std::vector<F>& vec)
    {
        // do some stuff
        vec.push_back(F());
        // do some more stuff
    }
}

我像这样使用它:

std::vector<F>(10) vec;
vec[0].doSomething(vec);

如果push_back(...)indoSomething(...)导致向量扩展会发生什么?这意味着vec[0]它将在执行其方法的过程中被复制然后删除。这可不好。

有人可以解释这里到底发生了什么吗?

  • 程序会立即崩溃吗?该方法是否只是尝试对不存在的数据进行操作?
  • 该方法是否对其对象进行“孤立”操作,直到遇到诸如更改对象状态之类的问题?

我对方法调用如何与关联对象相关感兴趣。

4

2 回答 2

7

是的,这很糟糕。当您在 doSomething() 中时,您的对象可能会被复制(或在 C++11 中移动,如果区别与您的代码相关)。所以 push_back() 返回后,this 指针可能不再指向你的对象的位置。对于 vector::push_back() 的特定情况,它指向的内存可能已被释放,并且数据可能已复制到其他地方的新数组中。对于其他将元素保留在适当位置的容器(例如列表),这(可能)根本不会引起问题。

实际上,您的代码不太可能立即崩溃。最可能的情况是对释放内存的写入和 F 对象状态的静默损坏。您可以使用 valgrind 之类的工具来检测这种行为。

但基本上你有正确的想法:不要这样做,这不安全。

于 2013-08-02T15:30:11.187 回答
3

有人可以解释这里到底发生了什么吗?

是的。如果您在 a 之后访问 object ,push_back或者resize重新insert分配了vector的内容,这是未定义的行为,这意味着实际发生的情况取决于您的编译器、您的操作系统、可能是什么do some more stuff以及可能还有许多其他因素,例如月相,某个遥远位置的空气湿度,......你的名字;-)

简而言之,这是(间接通过std::vector实现)调用对象本身的析构函数,因此对象的生命周期已经结束。此外,该对象先前占用的内存已被vector's 分配器释放。因此,使用对象的非静态成员会导致未定义的行为,因为this传递给函数的指针不再指向对象。但是,您可以访问/调用类的静态成员:

struct F
{
  static int i;
  static int foo();

  double d;
  void bar();

  // some member variables
  void doSomething(std::vector<F>& vec)
  {
    vec.push_back(F());

    int n = foo(); //OK
    i += n;        //OK

    std::cout << d << '\n'; //UB - will most likely crash with access violation
    bar();                  //UB - what actually happens depends on the 
                            //     implementation of bar
  }
}
于 2013-08-02T15:48:14.517 回答