在实现某个接口时,如头文件中所示,如何最好地防止库实现和头文件之间的危险不匹配?
详细信息:图书馆界面由头文件提供,例如foo.h
,以及某些源文件(例如foo.cc
)的实现。后者编译为创建库,比如libfoo.so
,而前者#include<>
由应用程序编辑,与libfoo.so
链接。
现在,假设在foo.h
// foo.h
namespace foo {
class bar
{
#ifdef SomeOption
std::int32_t x[2];
#else
std::int64_t x[2];
#endif
bar const*ptr;
/* ... */
};
}
然后ptr
的偏移量为8或16个字节,具体取决于SomeOption
(并且sizeof(bar)
也不同)。现在,如果使用与SomeOption
不同的值编译库而不是应用程序,那么显然会出现严重的问题(对于不知道的内容很难调试)。
解决方案?所以,我提出了以下想法
// foo.h
namespace foo {
enum { hasSomeOption = 1 };
int options_flags()
{
return 0
#ifdef SomeOption
| hasSomeOption
#endif
;
}
class bar
{
/* ... as before */
bar(some_args, int);
public:
bar(some_args) : bar(some_args, options_flags()) {} // what's option_flags()?
/* ... */
};
}
和
// foo.cc
namespace {
const int src_flags = options_flags(); // flags used for compiling library source
}
namespace foo {
bar::bar(some_args, int app_flags)
{
assert(app_flags == src_flags);
/* ... */
}
}
认为assert
会发现任何不一致之处。但是,这不起作用:编译器似乎优化了我的想法,并且断言永远不会触发,即使SomeOption
是
不同的库和应用程序编译。
问题对于此类问题,是否有推荐的最佳方法?
答案 0 :(得分:1)
我希望有更好的方法,但您可以随时根据选项更改类或命名空间名称,这样如果有人使用了错误的编译器选项,则无法找到该类。
更改命名空间的名称似乎更好 - 在使用调试器时不会引起很多混淆。像这样:
#ifdef SomeOption
#define foo foo_32bit
#else
#define foo foo_64bit
#endif
namespace foo
{
....
}
我想它会起作用,但肯定是丑陋的。