C++11环境下如何模拟检查容器的连续存储特性?
在C++11中判断容器是否具备连续存储特性
C20引入的contiguous_iterator trait能直接判断迭代器对应的存储是否连续,但在C11里我们只能通过一些“经验性”规则做尽力检测,以下是可行的实现思路和代码:
一、先处理已知的标准连续容器
对于std::vector<T>、std::array<T,N>、std::basic_string<T>这类明确连续存储的标准容器,直接通过模板特化标记为连续:
#include <vector> #include <array> #include <string> #include <type_traits> #include <iterator> // 基础模板,默认认为非连续 template <typename Container, typename = void> struct is_contiguous_container : std::false_type {}; // 特化std::vector template <typename T, typename Alloc> struct is_contiguous_container<std::vector<T, Alloc>> : std::true_type {}; // 特化std::array template <typename T, std::size_t N> struct is_contiguous_container<std::array<T, N>> : std::true_type {}; // 特化std::string及基础字符串模板 template <typename T, typename Traits, typename Alloc> struct is_contiguous_container<std::basic_string<T, Traits, Alloc>> : std::true_type {};
二、针对未知容器的推断逻辑
对于自定义容器或其他未知类型,我们可以基于两个必要条件做推断:
- 容器的迭代器必须是随机访问迭代器(连续存储的容器必然支持随机访问)
- 尝试验证容器首元素地址加上元素数量后,是否等于尾元素的下一个地址(仅当容器非空时有效)
结合SFINAE实现这个推断:
// 辅助判断迭代器是否为随机访问迭代器 template <typename It> using is_random_access_it = typename std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits<It>::iterator_category >::type; // 针对非标准容器的推断模板 template <typename Container> struct is_contiguous_container< Container, typename std::enable_if< is_random_access_it<typename Container::iterator>::value, void >::type > : std::integral_constant<bool, // 空容器直接返回true(避免取地址操作),非空则验证地址连续性 std::is_empty<Container>::value || ([]() { Container c; return c.empty() ? true : (&*c.begin() + c.size() == &*std::next(c.begin(), c.size())); })() > {}; // C++11版本的便捷检测函数 template <typename Container> constexpr bool is_contiguous(const Container& c) { if (is_contiguous_container<Container>::value) { return true; } // 先判断是否是随机访问迭代器 using It = typename Container::iterator; if (!std::is_base_of<std::random_access_iterator_tag, typename std::iterator_traits<It>::iterator_category>::value) { return false; } // 非空容器验证地址连续性 return c.empty() ? true : (&*c.begin() + c.size() == &*std::next(c.begin(), c.size())); }
三、局限性说明
这种检测是“尽力而为”的,存在以下限制:
- 无法正确识别
std::vector<bool>:它的迭代器是代理迭代器,虽然是随机访问,但存储不连续,会被误判为连续 - 自定义容器如果迭代器是随机访问但存储不连续,会误判
- 空容器的检测直接返回true,可能不符合部分自定义容器的实际情况(但空容器本身不存在存储连续性的实质问题)
内容的提问来源于stack exchange,提问作者einpoklum
相关产品推荐
相关产品推荐

