可能有人和我一样不喜欢使用MS的那些库,发布软件的时候得带一堆的DLL,更麻烦的是还要考虑版本问题,所以编写软件的时候都喜欢用MT和MTd编译参数。
使用QT的时候也一样。另外如果把QT的库全编译成LIB而不是DLL,搞得每个EXE一起步就是10M,看着也是不爽得很。那能不能QT用DLL,而不带MS的那些库呢?
经我实验,最后发现是基本不可能。
可能有人说他用MT和MTd参数编译了QT的DLL,用得挺好,但是事实上是这样的编译,某些代码可能不出问题,但是用到了某些功能那就是几乎一定会出错的。
比如examples\itemviews\addressbook那个程序,里面用到了QModelIndexList,如果用了MT和MTd参数编译的QT,那执行的时候就会导致HEAP错误,那是什么原因呢
?
问题在下面的代码(addresswidget.cpp的100行)
QTableView *temp = static_cast<QTableView*>(currentWidget());
QItemSelectionModel *selectionModel = temp->selectionModel();
QModelIndexList indexes = selectionModel->selectedRows();//这句
仔细调试发现indexes是在QT的DLL里构造的,析构是在EXE的函数退出的地方,由编译器自动产生代码析构,由于QModelIndexList实际上是QList<QModelIndex>,
是个模板类,他的析构函数会在EXE里实例化,导致在DLL的Heap里申请的内存结果归还到了EXE的Heap里(new操作调用的是malloc,malloc最后调用的是Heap函数,
Heap函数的使用请参考MSDN),这就是导致错误的原因。如果用的是MT和MTd编译的QT,那不管构造和析构是在DLL还是EXE,malloc函数是调用的MSVCRTXX.DLL里的函
数,所以最终操作的都是MSVCRTXX.DLL的Heap,所以不会出错。
如果要用MT和MTd编译,又不想出错的话,一个办法是将QModelIndexList的定义改了
原来是:
typedef QList<QModelIndex> QModelIndexList;
改成
class QModelIndexList:public QList<QModelIndex>
这样QModelIndexList由于不再是模板,他的析构函数会在DLL里,EXE会调用DLL里的析构函数去析构,可能就不会出错了。(猜的,没实验)
但是类似QModelIndexList这样的定义还有很多,要都改了工作量可不小,所以基本只能放弃了。