2010-01-09 67 views
2

我正在使用Qt(gui lib),VTK(图形库)和另一个如此晦涩的库的C++项目,我不会提及它的名称,而是将其称为LIB_X。该项目使用QT为gui组件和VTK(更确切地说是由VTK提供的支持Qt的QVTKWidget扩展)来渲染几何体,并使用LIB_X来收集和处理几何体。VC++库冲突问题

问题是,事实证明,LIB_X实际上使用VTK(在哪里以及如何,我不知道它是封闭的源代码)。起初没有问题,编译两个库链接都很好,但在某些时候,我调用了一个(并且非常需要)LIB_X函数,并且编译导致了一堆关于已经定义的VTK lib/obj的'blah blah'在LIB_X DLL'错误。

例如(并注意这与/ FORCE:多所以这是一个警告在这里,让我知道如果你想要的错误,而不/ FORCE:多,我会后):

1>LIB_X.lib(LIB_X.dll) : warning LNK4006: "public: __thiscall std::vector<double,class std::allocator<double> >::~vector<double,class std::allocator<double> >(void)" ([email protected][email protected]@[email protected]@@[email protected]@[email protected]) already defined in vtkCommon.lib(vtkInformationDoubleVectorKey.obj); 

我尝试使用/ FORCE: MULTIPLE,它起初似乎是一个奇迹,但是我得到的代码中的随机错误通常会导致堆错误。我决定从主项目中删除对LIB_X的所有引用,并创建一个静态库来处理所有LIB_X的东西。我不是C++专家,所以我不确定在使用预编译库时它是如何处理库冲突的,但是当我将静态库链接到我的主项目时仍然收到lib冲突错误,所以我仍然必须使用/ FORCE:MULTIPLE。

一旦我有了静态库,好像随机错误消失了,我可以通过静态库在主项目中使用LIB_X方法做很多事情,但是无处不在,我添加了一个新的数据成员到我的主要项目的类(一个std ::向量的双打),突然间我在我的一个静态库的方法中得到了一个堆错误。如果我注释掉了新的数据成员,静态库的方法会运行良好。我讨厌给当前的错误,因为老实说,我不确定是否检查它是值得的,但在这里它是无论如何,以防万一它可以帮助:

注意:它崩溃xutility约151行,弹出断言: “文件:dbgheap.c行:1279表达式:_CrtIsValidHeapPointer(pUserData)”

的错误出现添加矢量矢量双到矢量矢量矢量双,拍击的push_back行之后:

std::vector<std::vector<double>> tmpVec; 
for(srvl_iter = srvl.begin(); srvl_iter != srvl.end(); ++srvl_iter) 
{ 
tmpVec.push_back((*srvl_iter).getControlPoints()); 
} 
this->_splines.push_back(tmpVec); //CRASH 

当我向主项目中添加一个新的数据成员时,它只在这里崩溃(与静态分开lib!)注释掉新的数据成员会将错误消除。

std::vector<std::vector<std::vector<double>>> _geometry; 

因此,/ FORCE:MULTIPLE看起来不好,我得到的随机错误对我来说没有意义。还有其他解决方案吗?我拧了吗?有什么我可以用LIB_X连接VTK做什么?

回答

1

当我将应用程序链接到一个使用std::vector<std::string>的库(称为库LIB_Y)时,我遇到了一堆LNK4006错误,这也是我在我的应用程序中所做的。经过一番尝试后,我发现了一个解决方案 - 将LIB_Y封装在一个调用LIB_Y(LIB_Y_WRAPPER)的独立DLL中,然后将主应用程序与LIB_Y_WRAPPER相关联。

要尝试一下我的建议,你将需要:

  1. 改变从静态库项目成一个DLL项目(我会打电话给LIB_X_WRAPPER)你的“处理所有LIB_X东西静态库”。
  2. 确保LIB_X_WRAPPER的头文件不包含任何LIB_X头文件。这是非常重要的,因为包装需要将您的应用程序与LIB_X头文件中声明的数据类型(如std::vector<double>)完全隔离。仅从LIB_X_WRAPPER的源文件中引用LIB_X的头文件。
  3. 更改静态库中所有类和函数的声明以确保它们从DLL中导出(如果需要有关从DLL导出的详细信息,请参阅this answer)。

该解决方案为我工作,因为它一直由立白所使用的std::vector<std::string>类从std::vector<std::string>在我的应用程序的实例完全独立的实例(编译器生成的函数)。另外,我怀疑你看到的崩溃的原因(你评论它在std::vector<double>的析构函数中)是因为你的应用中的std::vector<double>的实例化与LIB_X中的不同。

+0

我在想,如果这样的事情能够发挥作用,我会尝试进行测试。 到目前为止,我的问题是#2,从包装中删除libx头。我需要libx中的数据成员在我的类中,他们需要libx命名空间来声明。该变量可能看起来像Libx :: DataStructA _dataStructA;我无法创建类原型,因为它需要名称空间,而且我不能使用名称空间,因为我没有头部访问,但是当涉及到可以解决此问题的名称空间时,我可能不知道有什么? – ferr 2010-01-10 18:33:24

+0

更多关于我上面的评论,我不确定它是否与名称空间有关,它只是一个前向声明问题,完全在很多级别上。我试图转发声明的libx类没有在我的类中声明为一个指针,所以它为此提出了一个合适的解决方案。将它声明为指针似乎没有多大帮助。 – ferr 2010-01-10 19:18:49

+0

好吧,在做了大量的搜索和搜索后,它看起来像你可以在类似这样的命名空间中声明一个类:namespace LibX {class libxClass; },这样我可以稍后声明一个LibX :: libxClass。我现在遇到的问题是我正在重新定义错误。我的.cpp文件中包含libxClass.h文件,它抱怨在我的头文件和libxClass.h文件中有一个定义。最重要的是,我试图转发声明的'class'实际上是一个类的typedef ..不知道对这种情况有什么影响。 – ferr 2010-01-10 22:30:31

0

注释可能只是随机运气 - 如果你正在破坏堆,你不会总是看到它,但一个stl向量将分配和释放左右的事情,所以难怪它找到了错误。

一些库需要你按照一定的顺序包括东西。我不确定为什么,因为我似乎放弃了,并说你不能正确设计一个图书馆,但这是一个可悲的事实。不过,只要你不包括这个lib_x在你包含vtk的地方,它应该没问题。

但是,他们可能会为某些资源而战,或者使用不适当的方式使他们无法一起工作。如果你能够通过隔离它们来使编译工作正常,那么它仍然会失败,那么你是不幸运的,因为这只是一个失败的方式,因为这是lib_x的设计方式,因为它很模糊,所以不太可能彻底调试所有用途。当某些东西没有被广泛使用时,它通常最终会成为开发者的机器和项目上的一些东西,但不一定是其他人的东西。

+0

我认为保持vtk和lib_x尽可能分开也会解决它。但我确实为我的lib_x创建了一个静态库。我只在这个静态库中的lib_x库中链接,当然在我的静态库中没有vtk链接。我的主项目没有链接任何lib_x库,但链接到静态库暴露了vtk和lib_x冲突。 有没有其他方法可以让它们更加分离? 最后的手段是我为lib_x制作一个单独的应用程序,将所有输出写入文本文件。它会慢得多,但它可能是一个临时解决方案。 – ferr 2010-01-09 21:32:26

+0

我一直在进一步研究它,我认为现在可能很明显,LIB_X和VTK都可能在争夺资源。 如果您查看链接器错误,它指定问题与多次定义的std :: vector相关。我经历了崩溃的调用堆栈,试图释放std :: vector之后崩溃了。崩溃的方法显然是试图释放已经被释放的东西。所以我猜想有两件事是试图释放一个向量。 – ferr 2010-01-10 01:56:39

+0

那么,你可以做的是编译和运行它们都作为完全独立的进程,并通过IPC或内存映射等将数据发送给它。不幸的是,你不能仅仅把它全部放到extern中,并且单独加载它,因为它不会初始化静态内容。在dll中,我认为所有版本都有自己的静态变量,所以如果你可以在单独的dll中编译它们呢?我不确定,通常我会像瘟疫一样避开它们,也许别人会知道。 – 2010-01-10 10:06:15