在哪些情况下,成员变量的声明顺序会影响程序的执行结果?

引力场变动源 2008-06-12 07:31:43
这几天在重新设计以前的一个程序,然后遇到了一个极为诡异的问题,已经2天了,相当头疼。
就是说,在一些类里面,成员变量(全是对象变量)的声明顺序会影响程序的运行结果。
目前已经对代码检查过很多遍了,各种更改测试也都做过,但是问题仍然存在。百思不得其解,所以想向大家请教一下,在那些情况下会出现这样的情况。

例子:
在CMainFrame类中定义有如下成员变量:

protected:
CStatusBar m_wndStatusBar;
CTimeBar m_TimeBar;
CSplitterWndEx m_wndSplitter;
CColorBar m_ColorBar;

其中CTimeBar和CColorBar是从CControlBar继承来的两种工具条。CSplitterWndEx是从CSplitterWnd继承来的窗体风格工具。
这三者的声明顺序不同会影响程序的运行结果,并且如果不把CColorBar放在最后的话,CColorBar在处理鼠标消息时会出现异常。但是将CColorBar放在最后的话,结束程序的时候会出现一个无法拦截的异常,程序将直接结束(伴有“当”的出错声音)而导致内存泄漏。

求解。
...全文
253 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
wuqiangu 2008-06-13
  • 打赏
  • 举报
回复
说到顺序就顺便提一下,一个潜规则:成员变量在构造函数中初始化列表的顺序,要和声明顺序一致!!

有可能不是你这个问题的原因,良好的编程习惯,可以避免一些莫名奇妙的错误。
shakaqrj 2008-06-13
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 cnzdgs 的回复:]
你在m_ColorBar的前后各定义一个数组(不要太大),在CMainFrame类的构造函数中将其初始化(例如[0]为0,[1]为0xff),调试程序看一下哪个数组会被修改,再在程序中设置一些断点,逐步缩小范围确认是哪个地方修改的。
[/Quote]
学习~~
jiqing_gao 2008-06-13
  • 打赏
  • 举报
回复
恩,应该与顺序无关,加油,我也mark一下
引力场变动源 2008-06-13
  • 打赏
  • 举报
回复
经过一上午的调试,发现将CColorBar类内如下两个成员的声明的顺序交换后错误可以消失:

bool m_IsButtonDown; //鼠标左键是否已经按下过
colorbar_button* m_SelectButton; //被选中的元素


具体的原因还不清楚。
zgl7903 2008-06-12
  • 打赏
  • 举报
回复
把临时文件都删了 工程打包法上来吧
Joephia 2008-06-12
  • 打赏
  • 举报
回复
同一个类,在别的工程下可以正常使用,在这边就怎么也调不好,真郁闷

是不是编译参数问题
引力场变动源 2008-06-12
  • 打赏
  • 举报
回复
同一个类,在别的工程下可以正常使用,在这边就怎么也调不好,真郁闷。
长尾巴的悟空 2008-06-12
  • 打赏
  • 举报
回复
与声明的顺序没有关系,你应该一步步的调.
让自己的思维与机器同步.
引力场变动源 2008-06-12
  • 打赏
  • 举报
回复
要崩溃了,实在找不到原因了……
引力场变动源 2008-06-12
  • 打赏
  • 举报
回复
结果之后再也没有发现数组被修改的情况,难道上一次看到数组被修改时调试器的幻象?
做鸡真好吃 2008-06-12
  • 打赏
  • 举报
回复
mark~有空看看
arong1234 2008-06-12
  • 打赏
  • 举报
回复
单步调试,看看到底做什么时候被改变的
[Quote=引用 10 楼 Silenker 的回复:]
引用 9 楼 Joephia 的回复:
vector <colorbar_button*> m_ButtonList

uint i;
for(i=0;i <m_ButtonList.size();++i)
{
delete m_ButtonList[i];
}


那个delete貌似没有问题的样子,换成delete m_ButtonList.at(i)或者换成

C/C++ code
vector<colorbar_button*>::iterator vi;
for(vi=m_ButtonList.begin();vi!=m_ButtonList.end();++vi)
{
delete (*vi);
}



的结果也…
[/Quote]
cnzdgs 2008-06-12
  • 打赏
  • 举报
回复
那就在m_ColorBar的后面加一个数组,定义稍大一些(例如1KB)再看是否被改变。
引力场变动源 2008-06-12
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 Joephia 的回复:]
vector <colorbar_button*> m_ButtonList

uint i;
for(i=0;i <m_ButtonList.size();++i)
{
delete m_ButtonList[i];
}
[/Quote]

那个delete貌似没有问题的样子,换成delete m_ButtonList.at(i)或者换成

vector<colorbar_button*>::iterator vi;
for(vi=m_ButtonList.begin();vi!=m_ButtonList.end();++vi)
{
delete (*vi);
}

的结果也是一样的。

刚刚跟踪发现,后面的数组在析构函数里面被改变了,正在做进一步的分析。
Joephia 2008-06-12
  • 打赏
  • 举报
回复
vector<colorbar_button*> m_ButtonList


CColorBar::~CColorBar()
{
uint i;
for(i=0;i<m_ButtonList.size();++i)
{
delete m_ButtonList[i];
}
m_ButtonList.clear();
m_GroupList.clear();
SAFE_DELETE(m_OnShader);
}

arong1234 2008-06-12
  • 打赏
  • 举报
回复
只有当有内存访问越界的问题时才可能。因为大家都知道变量顺序是不重要的,如果变量只访问自己的所属空间的话。但是如果有内存访问越界,则必然有某些无关变量被破坏,而随着你调整变量顺序,被破坏的变量则可能不同,则可能影响程序执行结果
引力场变动源 2008-06-12
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 cnzdgs 的回复:]
你在m_ColorBar的前后各定义一个数组(不要太大),在CMainFrame类的构造函数中将其初始化(例如[0]为0,[1]为0xff),调试程序看一下哪个数组会被修改,再在程序中设置一些断点,逐步缩小范围确认是哪个地方修改的。
[/Quote]

以在CColorBar前后各加一个数组以后,两个数组的值都没有被修改。但是错误消失。
去除前面的数组保留后面的数组时,数组的值没有被修改。但是错误消失。
去除后面的数组保留前面的数组时,数组的值没有被修改,但是错误出现。

元凶应该是CColorBar了吧……
cnzdgs 2008-06-12
  • 打赏
  • 举报
回复
你在m_ColorBar的前后各定义一个数组(不要太大),在CMainFrame类的构造函数中将其初始化(例如[0]为0,[1]为0xff),调试程序看一下哪个数组会被修改,再在程序中设置一些断点,逐步缩小范围确认是哪个地方修改的。
引力场变动源 2008-06-12
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 zzz3265 的回复:]
顺序没关系的, 可能是你的类里面的操作越界, 破坏了临近对象的数据, 所以...
[/Quote]

我也这么觉得的,但是实在找不到出现问题的地方……
引力场变动源 2008-06-12
  • 打赏
  • 举报
回复
CTimeBar类经过测试不管存在与否都与运行结果无关。另外一个类CSplitterWndEx的定义如下:

class CSplitterWndEx:public CSplitterWnd
{
private:
CColorX m_BorderColor; //边框颜色
CColorX m_BorderFillColor; //边框填充色
bool m_IsClick; //是否处于调整模式
public:
GET_SET_ACCESSOR(CColorX,BorderColor);
GET_SET_ACCESSOR(CColorX,BorderFillColor);
CSplitterWndEx();
public:
virtual void OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rect);
DECLARE_MESSAGE_MAP()
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
};

void CSplitterWndEx::OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rect)
{
// TODO: 在此添加专用代码和/或调用基类
int CX_BORDER=1,CY_BORDER=1;
if(pDC==NULL)
{
RedrawWindow(rect,NULL,RDW_INVALIDATE|RDW_NOCHILDREN);
return;
}
ASSERT_VALID(pDC);
CRect rc=rect;
switch(nType)
{
case splitBorder:
{
//重画分割窗口边界,使之为红色
pDC->Draw3dRect(rc,m_BorderColor.ToRGB(),m_BorderColor.ToRGB());
rc.InflateRect(-CX_BORDER,-CY_BORDER);
pDC->Draw3dRect(rc,m_BorderColor.ToRGB(),m_BorderColor.ToRGB());
break;
}
case splitBox:
{
pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
rc.InflateRect(-CX_BORDER,-CY_BORDER);
pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
rc.InflateRect(-CX_BORDER,-CY_BORDER);
pDC->FillSolidRect(rc,RGB(0,0,0));
pDC->Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
break;;
}
case splitBar:
{
//重画分割条,使之为绿色
pDC->FillSolidRect(rc,m_BorderFillColor.ToRGB());
break;
}
default:
ASSERT(FALSE);
}
}

CSplitterWndEx::CSplitterWndEx()
{
m_BorderColor=D3DCOLOR_ARGB(255,200,200,200);
m_BorderFillColor=D3DCOLOR_ARGB(255,150,150,150);
m_IsClick=false;
}

BEGIN_MESSAGE_MAP(CSplitterWndEx, CSplitterWnd)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

void CSplitterWndEx::OnLButtonDown(UINT nFlags, CPoint point)
{
CSplitterWnd::OnLButtonDown(nFlags, point);
GetGlobalEngine()->Stop();
}

void CSplitterWndEx::OnLButtonUp(UINT nFlags, CPoint point)
{
CSplitterWnd::OnLButtonUp(nFlags, point);
GetGlobalEngine()->Start();
}
加载更多回复(3)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧