老胡最近在工做中,有个场景须要使用一个第三方库,引用头文件,连接库,编译运行,一切都很正常,可是接下来就遇到了一个很诡异的问题,调用该库的中的一个对象方法为对象修改属性的时候,会影响到对象的另一个属性,当时百思不得其解,直呼灵异事件。
但后面静下心来细细看了一下代码和各类配置,发现了问题所在,如今把这个问题分享在这里,但愿你们在之后的工做中若是遇到了相似的状况知道应该如何处理。
ios
当时引用的是一个第三方的静态连接库,场景很是简单,在项目中包含头文件,连接器指定路径和静态库名称,咱们这里新建工程来生成一个很是简单的库。
this
其中,spa
//LibObject.h #pragma once struct LibObject { int valueA{ 0 }; #ifdef AdditionalValue int valueB{ 0 }; #endif int valueC{ 0 }; void DoSomething(); }; //LibObject.cpp #include "LibObject.h" void LibObject::DoSomething() { valueA = 10; #ifdef AdditionalValue valueB = 10; #endif }
简单至极,若预编译变量定义了AdditionalValue则定义多一个valueB而且在方法中赋值。编译库的时候咱们指定AdditionalValue。
指针
//main.cpp #include "LibObject.h" #include <iostream> using namespace std; int main() { LibObject obj; cout << obj.valueA << endl; cout << obj.valueC << endl; obj.DoSomething(); cout << obj.valueA << endl; cout << obj.valueC << endl; return 0; }
客户端代码也很简单,声明一个对象,调用它的方法并在调用先后检查它的值,在编译客户端代码的时候,咱们不定义AdditionalValue预编译变量。
code
如今猜一猜输出是多少?对象
若是这个结果让你吃惊,那么相信我,你不是一我的,当时老胡也惊呆了,无论怎么看,DoSomething仅仅修改了ValueA,为何会让ValueC的值变了?blog
秘密就在于编译库的时候和编译客户端代码的时候,咱们使用了不一样的预编译变量。事件
因此答案揭晓了,为何valueC的值会被影响,在于DoSomething执行的时候,至关于this指针偏移为4的int被赋值了,可是在咱们从客户端代码构建的结构体中,这个位置存放的是valueC。内存
从这里能够看出,在方法执行的过程当中,所谓的valueB其实内存地址和valueC是同样的。因此实际上是那句给valueB赋值的语句把值给了valueC。
文档
知道了出问题的地方,修复起来就很简单了,通常来讲两个办法。
这两个办法都须要仔细阅读第三方库的文档。 但愿本文能给遇到了相似问题的小伙伴一点启示,特别当你遇到了相似的状况的时候,这篇文章可以给你一些思路,毕竟,编译器甚至在这种状况下都不会给出任何警告,咱们只能靠经验排查了。