Mat*_*ths 3 c++ pointers vector
我最近在和一个学生一起工作时遇到了一个场景,我在努力理解以下示例失败的原因。
我有一个指向对象的指针Game,而Game它本身也有指向的指针vector<Pair>。失败的行是的最后一行main(),其中我采用菊花链方法:
gamePointer->getPairs()->push_back(pair);
在上面的行中,getPairs()返回vector<Pair>*,然后push_back()调用将一个新值添加Pair到向量中。结果是read access violation。有趣的是,换出Game的vector<Pair>一个string,比方说,让我写了以下内容,它的工作原理:
gamePointer->getPairs()->append("B");
我简化了问题,并复制了完整的示例:
#include "pch.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Pair
{
private:
string previous;
string next;
public:
Pair();
Pair(string previous, string next);
string getPrevious();
string getNext();
void setPrevious(string previous);
void setNext(string next);
};
class Game
{
private:
vector<Pair>* pairs;
public:
Game();
vector<Pair>* getPairs();
void setPairs(vector<Pair>* pairs);
};
Pair::Pair()
{
this->setPrevious("a");
this->setNext("b");
}
Pair::Pair(string previous, string next)
{
this->setPrevious(previous);
this->setNext(next);
}
string Pair::getPrevious()
{
return this->previous;
}
string Pair::getNext()
{
return this->next;
}
void Pair::setPrevious(string previous)
{
this->previous = previous;
}
void Pair::setNext(string next)
{
this->next = next;
}
Game::Game()
{
vector<Pair> pairs;
pairs.reserve(10);
this->setPairs(&pairs);
}
vector<Pair>* Game::getPairs()
{
return this->pairs;
}
void Game::setPairs(vector<Pair>* pairs)
{
this->pairs = pairs;
}
int main()
{
Game game;
Game* gamePointer = &game;
Pair pair("Previous", "Next");
gamePointer->getPairs()->push_back(pair);
}
Run Code Online (Sandbox Code Playgroud)
Game::Game()
{
vector<Pair> pairs; // DANGER!
pairs.reserve(10);
this->setPairs(&pairs); // ARGHH!
} // < pairs dies on this line
Run Code Online (Sandbox Code Playgroud)
该vector命名pairs构造函数运行时只活。您存储了指向该对象的指针,但是指向对象的对象立即超出范围!
而是将成员设为a vector而不是指针:
class Game
{
private:
vector<Pair> pairs; // the vector itself is a member of Game
Run Code Online (Sandbox Code Playgroud)
然后您可以getPairs这样:
vector<Pair>* Game::getPairs() // return a pointer
{
return &pairs;
}
Run Code Online (Sandbox Code Playgroud)
或这个:
vector<Pair>& Game::getPairs() // return a reference
{
return pairs;
}
Run Code Online (Sandbox Code Playgroud)
您当前正在做的事情是未定义的行为 -这意味着您的程序是非法的,并且可能会发生任何事情,包括看起来工作正常。
当您将换成vectora 时,您会看到“看起来正常工作”的内容string-您的代码仍然损坏,只是您没有注意到!
我可以对发生这种情况的原因进行有根据的猜测,但这绝不能保证。
vector 行为:
vector对象本身就是上堆叠,但是它必须在分配缓冲区堆使用new。delete当vector末尾超出范围时,将使用此缓冲区Game::Game()。vector对象本身不再有效,但内存恰好不会被覆盖之前,您接下来尝试使用它。vector,并且内存仍然碰巧包含指向缓冲区的指针。缓冲区已被释放,因此在尝试访问它时会遇到“读取访问冲突”。string 行为:
string不会不具有分配的缓冲区。它的有效实现是std::string使用“小字符串优化”,其中小字符串(例如,最多16个字符)直接存储在string对象本身内部,而不是存储在分配的缓冲区中。string,包括实际内容在内的都在堆栈上。string对象在的末尾超出范围Game::Game(),但是在您下次尝试使用它之前,内存恰好不会被覆盖。string,并且内存仍然碰巧包含有效的“短字符串”魔术。