移植代码到 DLL 时遇到的一个问题

有一个功能模块, 本来是写在主程序当中. 现在觉得有必要将它写成一个 DLL. 于是开始代码的移植. 费了好大的劲. 终于移植完成, 通过编译了. 这时运行程序, CRASH!
调试之, 发现是在一个 map 的赋值出现了问题.
看 vc6 自带的 STL 的代码:

map 的赋值操作, 也就是其中的树赋值操作.
_Myt& operator=(const _Myt& _X)
{
    _Tr = _X._Tr;
    return (*this);
}

树的赋值操作:
_Myt& operator=(const _Myt& _X)
{
    if (this != &_X)
    {
        erase(begin(), end());
        key_compare = _X.key_compare;
        _Copy(_X);
    }
    return (*this);
}
先删除自己, 然后调用 _Copy(const _Myt&);

void _Copy(const _Myt& _X)
{
    _Root() = _Copy(_X._Root(), _Head);
    _Size = _X.size();
    if (_Root() != _Nil)
    {
        _Lmost() = _Min(_Root());
        _Rmost() = _Max(_Root());
    }
    else
        _Lmost() = _Head, _Rmost() = _Head;
}

其中又调用了 _Copy(_Nodeptr, _Nodeptr);

_Nodeptr _Copy(_Nodeptr _X, _Nodeptr _P)
{
    _Nodeptr _R = _X;
    for (; _X != _Nil; _X = _Left(_X))      // error here
    {
        _Nodeptr _Y = _Buynode(_P, _Color(_X));
        if (_R == _X)
            _R = _Y;
        _Right(_Y) = _Copy(_Right(_X), _Y);
        _Consval(&_Value(_Y), _Value(_X));
        _Left(_P) = _Y;
        _P = _Y;
    }
    _Left(_P) = _Nil;
    return (_R);
}

看标记的那一行. _X 与 _Nil 比较. 其中的 _Nil 如下:
static _Tree<_K, _Ty, _Kfn, _Pr, _A>::_Nodeptr _Tree<_K, _Ty, _Kfn, _Pr, _A>::_Nil = 0;

是一个静态变量. 初始值为 0. 在一个 module (注: 这里的 module 是指的一个exe, 或者 dll. 下同) 中构建第一个 map 实例时, 有这样的代码:
                if (_Nil == 0)
                        {_Nil = _Buynode(0, _Black);
                        _Left(_Nil) = 0, _Right(_Nil) = 0; }

如果 _Nil 未初始化则创建一个 node, 初始化 _Nil. 然后 map 将内部的 _Head._Parent 指向这个 _Nil.

设想这样一种情形. 一个 EXE, 一个 DLL.
                       
EXE:
void main()
{
 map m;
 func(m);
}

DLL:
void func(map& m)
{
 map n = m;
}

在 EXE 中构建了一个 map 实例. 然后传到 DLL 中做赋值操作.
分析执行过程, 首先 EXE 中的 m 初始化, 完成之后 m._Head._Parent  指向了一个 _Nil 节点. 然后这个 m 传到 dll 中. 此时, n 进行初始化, 又执行这样的代码:
                if (_Nil == 0)
                        {_Nil = _Buynode(0, _Black);
                        _Left(_Nil) = 0, _Right(_Nil) = 0; }

注意, 在 DLL 中, 这里的 _Nil 为 0. 因为这个 _Nil 和 EXE 中的 _Nil 并不是同一份拷贝. 因此又会创建一个 node, 然后让 _Nil 指向它. 再让 n._Head._Parent 指向这个 _Nil.
问题在这里开始出现了. map 的代码认为其所有的实例的 _Head._Parent 都指向同一个 _Nil. 但这里已经违背了这个原则.
最终的结果就是 crash. 在这个例子中, crash 出现在 _Copy(_Nodeptr, _Nodeptr) 函数中. 

下载示例源码. (右击, 目标另存为.., 得到一 .png, 改名为 .rar) 如果要编译其中的代码. 比如使用 vc6, 可以执行 C:/Program Files/Microsoft Visual Studio/VC98/Bin/VCVARS32.BAT 然后在其中用命令行编译.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值