Visual C++ 2015 中标量类型的矢量专业化消失了吗?
Vector specialization for scalar types gone in Visual C++ 2015?
在将我们的项目升级到 Visual Studio 2015 时,我们遇到了破坏大型 vector<unsigned char>
的问题,它正在存储图像 - 大约 5 Mb。在 Debug 构建中,它花费了大约 0.5 秒,而对于 char(一种 POD
类型),这应该 - 原则上 - 只有一个内存释放调用。
调试器显示 VS 2015 (VC 14.0) 中的实现遍历已析构数组中的每个元素并调用其析构函数 - 无论它是 POD
类型还是复杂类型.所以我理解了这个问题以及为什么它只发生在调试版本中——在发布版本中,编译器足够聪明,可以删除不必要的空函数调用。
实际上 Visual Studio 的所有先前版本中都有标量类型的专门化(2003 年和 2012 年检查):
template<class _Alloc> inline
void _Destroy_range(typename _Alloc::pointer _First,
typename _Alloc::pointer _Last, _Alloc& _Al,
_Scalar_ptr_iterator_tag)
{ // destroy [_First, _Last), scalar type (do nothing)
}
但现在它不见了,我们只有
template<class _Alloc> inline
void _Destroy_range(typename _Alloc::pointer _First,
typename _Alloc::pointer _Last, _Alloc& _Al)
{ // destroy [_First, _Last)
for (; _First != _Last; ++_First)
_Al.destroy(_STD addressof(*_First));
}
我只是不明白为什么要删除这个有用且简单的优化。而且我找不到微软对此的任何评论。
问题:
- 有人知道这种变化的原因吗?
- 有没有办法在不更改我们代码中的每个 POD 向量(自定义容器或
unique_ptr<type[]>
/ boost::scoped_array
)的情况下解决销毁缓慢的问题?
你的理论似乎是正确的,他们最近取消了专业化,它看起来像一个错误。团队中的一位开发人员表示,之所以做出更改,是因为有些构造函数没有被调用,但应该被调用。这个新版本在技术上可能更正确,但对调试有可怕的性能影响。
我也遇到了这个问题。这是我的测试程序:
int main()
{
auto foo = new std::vector<unsigned char>(100 * 1000 * 1000);
delete foo;
return 0;
}
这在 VS 2015 w/toolset=vc120 中运行约 54ms,而在 toolset=vc140 中运行约 11,000ms。所有时间都花在删除行上。
我还没有找到解决方法。
在将我们的项目升级到 Visual Studio 2015 时,我们遇到了破坏大型 vector<unsigned char>
的问题,它正在存储图像 - 大约 5 Mb。在 Debug 构建中,它花费了大约 0.5 秒,而对于 char(一种 POD
类型),这应该 - 原则上 - 只有一个内存释放调用。
调试器显示 VS 2015 (VC 14.0) 中的实现遍历已析构数组中的每个元素并调用其析构函数 - 无论它是 POD
类型还是复杂类型.所以我理解了这个问题以及为什么它只发生在调试版本中——在发布版本中,编译器足够聪明,可以删除不必要的空函数调用。
实际上 Visual Studio 的所有先前版本中都有标量类型的专门化(2003 年和 2012 年检查):
template<class _Alloc> inline
void _Destroy_range(typename _Alloc::pointer _First,
typename _Alloc::pointer _Last, _Alloc& _Al,
_Scalar_ptr_iterator_tag)
{ // destroy [_First, _Last), scalar type (do nothing)
}
但现在它不见了,我们只有
template<class _Alloc> inline
void _Destroy_range(typename _Alloc::pointer _First,
typename _Alloc::pointer _Last, _Alloc& _Al)
{ // destroy [_First, _Last)
for (; _First != _Last; ++_First)
_Al.destroy(_STD addressof(*_First));
}
我只是不明白为什么要删除这个有用且简单的优化。而且我找不到微软对此的任何评论。
问题:
- 有人知道这种变化的原因吗?
- 有没有办法在不更改我们代码中的每个 POD 向量(自定义容器或
unique_ptr<type[]>
/boost::scoped_array
)的情况下解决销毁缓慢的问题?
你的理论似乎是正确的,他们最近取消了专业化,它看起来像一个错误。团队中的一位开发人员表示,之所以做出更改,是因为有些构造函数没有被调用,但应该被调用。这个新版本在技术上可能更正确,但对调试有可怕的性能影响。
我也遇到了这个问题。这是我的测试程序:
int main()
{
auto foo = new std::vector<unsigned char>(100 * 1000 * 1000);
delete foo;
return 0;
}
这在 VS 2015 w/toolset=vc120 中运行约 54ms,而在 toolset=vc140 中运行约 11,000ms。所有时间都花在删除行上。
我还没有找到解决方法。