【问题标题】:How to check whether a container is stable如何检查容器是否稳定
【发布时间】:2013-05-18 13:42:11
【问题描述】:

std::vector 是一个不稳定的容器,即通过调整向量的大小,迭代器可能会失效。 相比之下,std::listboost::container::stable_vector 是稳定的容器,它们保持迭代器有效,直到删除相应的元素。

有没有办法检查给定容器是否稳定?例如,如果我有类似的东西

template<template <typename A, typename B=std::allocator<A> > class T=std::list>
class Foo
{
}

是否可以只允许稳定的容器而禁止不稳定的容器?

【问题讨论】:

  • 有趣的问题。
  • 这就是我们需要概念的原因! (我认为)
  • @MarkGarcia:事实上,这就是我们需要axioms的原因。没有公理的概念无法捕捉到这样的语义要求。不过,我不确定我们是否会很快拥有它们……

标签: c++ stl iterator containers


【解决方案1】:

我认为没有任何东西可以提供此类信息,但您可以编写自己的特征。但是,您需要为每个可能使用的稳定容器专门化它,这可能不是一个选择。

#include <boost/container/vector.hpp>

#include <iostream>
#include <type_traits>
#include <list>
#include <vector>

template <template <typename...> class Container>
struct is_stable
    : std::false_type
{};

template <>
struct is_stable<std::list>
    : std::true_type
{};

template <>
struct is_stable<boost::container::stable_vector>
    : std::true_type
{};

template<template <typename...> class Container = std::list>
class Foo
{
    static_assert(is_stable<Container>::value, "Container must be stable");
};

int main()
{
    Foo<std::list> f1; // ok
    Foo<std::vector> f2; // compiler error
}

我认为没有一种方法可以自动检测容器是否稳定,而无需借助手动专门化。


只是为了好玩,我尝试编写稳定性的概念/公理(conceptsaxioms 是对 considered for inclusion in C++11 语言的扩展):

concept StableGroup<typename C, typename Op>
    : Container<C>
{
    void operator()(Op, C, C::value_type);

    axiom Stability(C c, Op op, C::size_type index, C::value_type val)
    {
        if (index <= c.size())
        {
            auto it = std::advance(c.begin(), index);
            op(c, val);
            return it;
        }
        <->
        if (index <= c.size())
        {
            op(c, val);
            return std::advance(c.begin(), index);
        }
    }
}

如果认为这正确捕获了原始容器上的每个迭代器都等效于修改后容器上的相应迭代器的要求。不确定这是否很有用,但提出这样的公理是一个有趣的练习:)!

【讨论】:

  • 这绝对正确——稳定/不稳定是一个非常抽象的概念。向量可能不会轻易地使其迭代器无效:当您认为它可以调整数组大小时,它可能不会调整数组大小,或者即使它这样做,它也可能能够扩展它使用的现有内存块(取决于编译器等)。如果我编写自己的容器,它可以很容易地不确定地重新分配内存。
  • 例如,如果您不包含带有boost::stable_vector 的标头,则此特征会中断。为了普遍使用,您还需要转发声明您专门针对的所有类。
  • @jrok:是的,这就是为什么这个解决方案远非理想。理想情况下,容器库有责任专门化特征,但这显然不是一种选择。另一种可能性是让 trait 保持非特化(除了最常见的容器)并向Foo 用户指示如果他们希望使用另一个容器,他们必须特化该 trait:static_assert 会引起他们对这部分的注意该文档应该非常清楚地表明容器必须是稳定的。不过还是不太方便。
猜你喜欢
  • 1970-01-01
  • 2021-12-19
  • 1970-01-01
  • 2012-05-16
  • 2016-09-15
  • 1970-01-01
  • 2022-12-23
  • 2012-11-06
  • 1970-01-01
相关资源
最近更新 更多