解决"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并没有这么严格,所以一般可以编译过。这里顺便列一下最新的标准里,模板参数的要求,以后写代码时尽量注意一下。

StandardRequirement for T
C++03any type
C++11any non-const, non-reference object type
C++14any non-const object type
C++17any cv-unqualified object type

解决

由于C++模板的特殊性,一般模板的报错信息都非常“谜”。在我本机,报错信息是指向了xmemory0文件,但其实不是这个文件出错,而是因为我们自身的代码在STL容器模板中使用了const导致出错的。
可以通过文本查找“<const”,基本能找到项目中大部分在模板中使用了const的代码,将其中的const去掉即可。如果找不全,可以试下:< constconst>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));

	// ...
}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐