所有上述答案都提到了C++11和GCC,但没有提到在GCC中的_GLIBCXX_USE_CXX11_ABI编译定义,这还不够。
使用-std=c++11进行编译并不意味着在GCC中std::list::size()是O(1),它默认是O(1),但是当使用_GLIBCXX_USE_CXX11_ABI=0进行编译时,它变成了O(N)。
GCC版本小于5.1,例如GCC4.8支持C++11,但无论你使用什么编译标志,std::list::size()都是O(N)。
这可以在当前GCC的源代码中清楚地显示出来:size()的实现如下。
_GLIBCXX_NODISCARD
size_type
size() const _GLIBCXX_NOEXCEPT
{ return _M_node_count(); }
它被称为_M_node_count(),而_M_node_count的实现如下所示:
#if _GLIBCXX_USE_CXX11_ABI
static size_t
_S_distance(const_iterator __first, const_iterator __last)
{ return std::distance(__first, __last); }
size_t
_M_node_count() const
{ return this->_M_get_size(); }
#else
static size_t
_S_distance(const_iterator, const_iterator)
{ return 0; }
size_t
_M_node_count() const
{ return std::distance(begin(), end()); }
#endif
如果_GLIBCXX_USE_CXX11_ABI设置为0,size()的复杂度为O(N),否则为O(1)。
当你使用高版本GCC编译的库并且需要链接到低版本GCC编译的库时,_GLIBCXX_USE_CXX11_ABI设置为0会发生。例如,你的系统安装了一个GCC 4.8编译的GTEST库,但是你的代码现在使用GCC 7.3和C++11,并且你需要链接到那个库,在这种情况下,你需要在你的CMakeLists.txt中添加以下内容,否则会出现链接问题。
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0)
总之,在GCC中,
- 当使用GCC版本小于5.1时,std::list::size()的时间复杂度为O(N)。
- 当使用GCC版本大于等于5.1时:
- 当编译选项中设置了_GLIBCXX_USE_CXX11_ABI=0时,std::list::size()的时间复杂度为O(N)。
- 当编译选项中未设置_GLIBCXX_USE_CXX11_ABI或设置了_GLIBCXX_USE_CXX11_ABI=1时,std::list::size()的时间复杂度为O(1)。