以下程序的意外行为(只要我能做到):
#include <vector>
#include <iostream>
class Entry;
class CachedPayload {
public:
CachedPayload(const Entry* const o) : owner_(o) {}
void info(const char* where);
private:
const Entry* const owner_;
// meaningful payload not shown in this minimal example
};
class Entry {
public:
Entry(int i) : cached(this), my_i(i) {}
void showEntry(const char* where) const {
std::cout << where << ": this=" << this << ", i=" << my_i << std::endl; }
CachedPayload cached;
private:
int my_i;
};
void CachedPayload::info(const char* where) { owner_->showEntry(where); }
class CachingVector {
public:
CachingVector() {
resize();
data_.at(0).cached.info("GET");
}
void resize() {
data_.push_back(Entry(97));
data_.at(0).cached.info("RSZ");
}
private:
std::vector<Entry> data_;
};
int main()
{
CachingVector vec;
}
结果:
$ clang++-6.0 h.cpp && a.out
RSZ: this=0x7ffe1dc52dc8, i=97
GET: this=0x7ffe1dc52dc8, i=4206609
$ g++ h.cpp && a.out
RSZ: this=0x7ffc5e977040, i=97
GET: this=0x7ffc5e977040, i=-578764228
为什么通过vec.data_[0].my_i
访问vec.data_[0].cached.owner_
的值时,会以无意义的,依赖于编译器的方式覆盖{1>?
当我将两行实现的CachingVector::resize()
合并到构造函数CachingVector()
中时,i=97
不会受到破坏。
答案 0 :(得分:3)
您正在向量中存储一个指向临时变量的指针(特别是在CachedPayload::owner_
中)。这就是问题的原因。临时文件销毁后,您将拥有一个悬空的指针。
我已将此添加到您的代码中
~Entry() { std::cout << "destroyed " << this << std::endl; }
还有这个
CachingVector() {
data_.reserve(1); // prevent reallocation
resize();
data_.at(0).cached.info("GET");
}
新输出为
destroyed 00000000001AF588
RSZ: this=00000000001AF588, i=97
GET: this=00000000001AF588, i=-858993460
如您所见,您正在访问的对象已被破坏,这当然是未定义的行为。
要解决此问题,我认为您只需为Entry
定义一个复制构造函数和赋值运算符,以确保cached.owner_
始终具有正确的值。
Entry(const Entry& rhs) : cached(this), my_i(rhs.my_i) {}
Entry& operator=(const Entry& rhs) { my_i = rhs.my_i; return *this; }