解决"Error C2338 The C++ Standard forbids containers of const elements because allocator"问题
最近在用Visual Studio 2017编译Brofiler(一个C++的Profiler)时,遇到了一些问题,其中一个就是这个Error C2338。
原因
因为在STL容器模板中使用了const
,在C++11的标准里,这是禁止的!而老版本的Visual Studio并没有这么严格,所以一般可以编译过。这里顺便列一下最新的标准里,模板参数的要求,以后写代码时尽量注意一下。
Standard | Requirement for T |
---|---|
C++03 | any type |
C++11 | any non-const, non-reference object type |
C++14 | any non-const object type |
C++17 | any cv-unqualified object type |
解决
由于C++模板的特殊性,一般模板的报错信息都非常“谜”。在我本机,报错信息是指向了xmemory0文件,但其实不是这个文件出错,而是因为我们自身的代码在STL容器模板中使用了const
导致出错的。
可以通过文本查找“<const
”,基本能找到项目中大部分在模板中使用了const
的代码,将其中的const
去掉即可。如果找不全,可以试下:< const
、const>
、const >
等情况,或者通过正则表达式来查找。
例如在Brofiler 1.1.2的源码中,就有2处地方使用了const
。注意去掉了容器定义里的const
后,一般还会导致部分容器使用的代码报错,我们可以用const_cast
来去掉代码里的const限定,如下:
// 文件:Core.h
// FIX Error C2338
//typedef MemoryPool<const EventData*, 32> CategoryBuffer;
typedef MemoryPool<EventData*, 32> CategoryBuffer;
BRO_INLINE void RegisterCategory(const EventData& eventData)
{
// FIX Error C2338
//categoryBuffer.Add() = &eventData;
categoryBuffer.Add() = const_cast<EventData*>(&eventData);
}
// 文件:Sampler.cpp
OutputDataStream& Sampler::Serialize(OutputDataStream& stream)
{
// ...
// FIX Error C2338
//std::vector<const Symbol * const> symbols;
std::vector<Symbol*> symbols;
for each (DWORD64 address in addresses)
if (auto symbol = symEngine.GetSymbol(address))
//symbols.push_back(symbol);
symbols.push_back(const_cast<Symbol*>(symbol));
// ...
}