这不是一个关于你为什么要编写这样的代码的问题,而是一个关于方法如何与它所依赖的对象相关的问题。
如果我有一个结构:
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(...)
中的doSomething(...)
导致向量扩展会怎样?这意味着vec[0]
将被复制,然后在执行其方法时被删除。这不好。
有人能解释一下这里究竟发生了什么吗?
我对方法调用与关联对象的关系感兴趣。
答案 0 :(得分:7)
是的,这很糟糕。当你在doSomething()中时,你的对象可能被复制(或者在C ++ 11中被移动,如果区别与你的代码相关)。因此,在push_back()返回后,this指针可能不再指向对象的位置。对于vector :: push_back()的特定情况,可能已释放此指向的内存,并将数据复制到其他位置的新数组中。对于将其元素留在原位的其他容器(例如列表),这(可能)根本不会导致问题。
实际上,您的代码不太可能立即崩溃。最可能的情况是写入空闲内存和F对象状态的静默损坏。您可以使用valgrind之类的工具来检测这种行为。
但基本上你有正确的想法:不要这样做,这不安全。
答案 1 :(得分:3)
有人能解释一下这里究竟发生了什么吗?
是。 如果您访问该对象,在push_back
,resize
或insert
重新分配了vector
的内容后,这是未定义的行为,这意味着什么实际发生取决于您的编译器,您的操作系统,do some more stuff
是什么以及可能还有许多其他因素,例如可能是月相,某些遥远位置的空气湿度,......你将它命名; - )
简而言之,这是(通过std::vector
实现)间接调用对象本身的析构函数,因此对象的生命周期已经结束。此外,vector
的分配器已释放先前由对象占用的内存。因此,使用对象的非静态成员会导致未定义的行为,因为传递给函数的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
}
}