gpt4 book ai didi

c++ - STL List 复制一个结构,但复制的值偏移了两个内存地址

转载 作者:行者123 更新时间:2023-11-27 22:30:25 24 4
gpt4 key购买 nike

我正在使用 MinGW 编译器在 Windows 7 上使用 Code::Blocks 进行编译(我只能假设它是最新版本;Code::Blocks 和 MinGW 都是上周安装的)。我的问题是在特定情况下突然出现的,我尝试编写一个更简单的脚本来演示该问题失败了(这意味着我的结构有问题)。另外,对于这篇文章的篇幅,我深表歉意。

目前,我正在使用一个类 FXSDL,它将充当 SDL 包装器:

class FXSDL
{
public:
FXSDL();
virtual ~FXSDL();
int Initialize();
int Render();

FXID CreateCharacter(FXID hRefID, string fpImage, int wpxTile, int hpxTile, map<int, vector<int> > htAnims);
int SetAnim(FXID hRefID, FXID hAnimID);
FXID hPlayer;
protected:
private:
list<FXSurface> m_lstFXObjects;
list<FXSurface>::iterator m_liFirst;
SDL_Surface* m_lpsfSDLScreen;
Uint32 m_tmOld;
Uint32 m_tmFrame;
};

我的列表的值类型是:

struct FXSurface
{
FXID hRefID;
int wpxTile;
int hpxTile;
int wpxTotal;
int hpxTotal;
int cntTiles;

map<int, vector<int> > htAnims; // All animations
map<int, vector<int> >::iterator vCurr; // Currently active animation
vector<int>::iterator fiCurr; // Currently active frame
SDL_Surface* lpsfSDL;
SDL_Rect* lprcTiles; // Predefined frame positions
string* fpImage;
};

我已经实现了非常简单的初始化和渲染功能。 CreateCharacter 函数有几个参数,其中最重要的是 htAnims,一个整数 vector 映射(想法是:我用易于内存的表示形式定义数字 id,例如 FXA_IDLE 或 FXA_WALK,作为键,以及系列表示动画帧的数值作为 vector )。这可以很容易地实现为多维整数数组,但动画的长度是可变的,我希望能够添加新动画(或重新定义现有动画)而无需重新转换数组。

CreateCharacter 函数很简单。它创建一个新的 FXSurface,用所需的数据填充它,并将新的 FXSurface 推送到列表中:

FXID FXSDL::CreateCharacter(FXID hRefID, string fpImage, int wpxTile, int hpxTile, map<int, vector<int> > htAnims)
{
//list<FXSurface>::iterator lpsfTemp;
FXSurface lpsfTemp;
list<FXSurface>::iterator lpsfPos;
SDL_Rect* lprcCurr = NULL;
int cntTileW = 0;
int cntTileH = 0;
int cntCurr = 0;

// Start off by initializing our container struct
//lpsfTemp = new FXSurface();
lpsfTemp.lpsfSDL = IMG_Load(fpImage.c_str()); // Try to load the requested image
if(lpsfTemp.lpsfSDL != NULL) // If we didn't fail to
{
// Assign some variables for tracking
lpsfTemp.hRefID = hRefID;
lpsfTemp.fpImage = &fpImage;
lpsfTemp.wpxTotal = lpsfTemp.lpsfSDL->w;
lpsfTemp.hpxTotal = lpsfTemp.lpsfSDL->h;

// If a tile width was specified, use it
if(wpxTile != 0)
{
lpsfTemp.wpxTile = wpxTile;
lpsfTemp.hpxTile = hpxTile;
} // Otherwise, assume one tile
else
{
lpsfTemp.wpxTile = lpsfTemp.wpxTotal;
lpsfTemp.hpxTile = lpsfTemp.hpxTotal;
}

// Determine the tiles per row and column for later
cntTileW = lpsfTemp.wpxTotal / lpsfTemp.wpxTile;
cntTileH = lpsfTemp.hpxTotal / lpsfTemp.hpxTile;

// And the total number of tiles
lpsfTemp.cntTiles = cntTileW * cntTileH;
lpsfTemp.lprcTiles = new SDL_Rect[cntTileW*cntTileH];

// So we don't calculate this every time, determine each frame's coordinates and store them
for(int h = 0; h < cntTileH; h++)
{
for(int w = 0; w < cntTileW; w++)
{
cntCurr = (h*cntTileW)+w;
lprcCurr = new SDL_Rect;
lprcCurr->w = lpsfTemp.wpxTile;
lprcCurr->h = lpsfTemp.hpxTile;
lprcCurr->x = w*lpsfTemp.wpxTile;
lprcCurr->y = h*lpsfTemp.hpxTile;

lpsfTemp.lprcTiles[cntCurr] = *lprcCurr;
lprcCurr = NULL;
}
}

// Now acquire our list of animations and set the default
//lpsfTemp.htAnims = new map<int, vector<int> >(*htAnims);
lpsfTemp.htAnims = htAnims;
lpsfTemp.vCurr = lpsfTemp.htAnims.find(FXA_WALK_EAST);
lpsfTemp.fiCurr = lpsfTemp.vCurr->second.begin();

this->m_lstFXObjects.push_back(lpsfTemp);
}
else
{
hRefID = 0;
}

return hRefID;
}

正是在推送对象时发生了错误。我已经多次遍历代码。最初,我只能说我的迭代器无法解除对 FXSurface 对象的引用。在使用 watches 识别迭代器和列表对象指向的确切内存地址并取消引用该地址后,我注意到了我的段错误的原因:当列表时,我放入原始 FXSurface 的所有值都被向下推了两个内存块对象复制了它!

我这样做的过程很简单。我在 CreateCharacter 的返回语句处设置了一个断点,这使我可以查看 lpsfTemp(我稍后添加到列表中的 FXSurface)和 m_lstFXObjects(我将其添加到的列表)。我滚动浏览 m_lstFXObjects 的成员,这将我带到 _M_node,其中包含我目前添加的唯一对象的内存地址。我以(FXSurface)-hex address here-

的形式向这个地址添加了一个watch

首先,找到地址:

(这里应该有一张图片高亮显示包含列表项地址的_M_node属性,但是我不能发图片,只能发一个URL,第二个更重要,它位于http://www.fauxsoup.net/so/address.jpg )

接下来,我们强制转换地址。此图像同时显示了 lpsfTemp 和 m_lstFXObjects 中的拷贝;注意到差异了吗?

http://www.fauxsoup.net/so/dereferenced.jpg - 看到了吗?所有值的顺序都是正确的,只是偏移了两个列表

我最初将 fpImages 存储为一个 char*,所以我认为这可能会导致错误,但现在它只是一个指针,问题仍然存在。也许这是由于我存储的 map >?

最佳答案

FXSDL 有一个析构函数,但是没有复制构造函数没有赋值运算符。你在使用裸指针,但违反了 Rule of Three .

我不会再看下去了。

使用智能指针来管理资源。不要将裸资源放入类型中,除非该类型的唯一目的是管理这一资源。来自 another answer昨天给出:

As a rule of thumb: If you have to manually manage resources, wrap each into its own object.

关于c++ - STL List 复制一个结构,但复制的值偏移了两个内存地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3206504/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com