gpt4 book ai didi

c++ - 通过在迭代指针键映射上出错来捕获不确定性

转载 作者:行者123 更新时间:2023-11-30 03:15:17 30 4
gpt4 key购买 nike

我们已经在我正在处理的代码库中发现了几次不确定性问题,到目前为止,这几乎是使用 std::[unordered_]map/set<T*,U> 的根本原因。 ,其中键是一个指针,与 map 上的迭代相结合,通常采用基于范围的 for 循环的形式(因为指针值可能在执行之间发生变化,迭代顺序是不确定的)。

我想知道是否有一些黑色模板魔法可以用来注入(inject) static_assert什么时候begin()在这样的容器上调用。我想begin()是最好的地方,或者可能是iterator::operator++ ,因为以其他方式构造迭代器,例如 find() 的结果, 没关系。

我以为我可以重载 std::begin ,但是基于范围的 for 循环的规则规定 .begin()如果存在则使用。所以,我没主意了。有什么巧妙的技巧可以做到这一点吗?

进一步说明:不涉及自定义比较器,指针的直接值(即目标对象的地址)是关键。这对于插入和查找来说很好,只有在遍历容器时才会成为问题,因为顺序是基于不可预测的指针值。我正试图在现有的大型代码库中找到这样的现有案例。

最佳答案

您几乎可以通过偏特化实现所需的行为:

20.5.4.2.1 The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.

因此,std::map 的简单特化可用于检测使用指针键类型实例化模板的尝试:

#include <map>

namespace internal
{
// User-defined type trait
template<class Key, class T>
class DefaultAllocator
{
public:
using type = std::allocator<std::pair<const Key, T>>;
};

// Effectively the same as std::allocator, but a different type
template<class T>
class Allocator2 : public std::allocator<T> {};
}

namespace std
{
// Specialization for std::map with a pointer key type and the default allocator.
// The class inherits most of the implementation from
// std::map<Key*, T, Compare, ::internal::Allocator2<std::pair<Key*, T>>>
// to mimic the standard implementation.
template<class Key, class T, class Compare>
class map<Key*, T, Compare, typename ::internal::DefaultAllocator<Key*, T>::type> :
public map<Key*, T, Compare, ::internal::Allocator2<std::pair<Key*, T>>>
{
using base = map<Key*, T, Compare, ::internal::Allocator2<std::pair<Key*, T>>>;
using base::iterator;
using base::const_iterator;

public:
// Overload begin() and cbegin()
iterator begin() noexcept
{
static_assert(false, "OH NOES, A POINTER");
}
const_iterator begin() const noexcept
{
static_assert(false, "OH NOES, A POINTER");
}
const_iterator cbegin() const noexcept
{
static_assert(false, "OH NOES, A POINTER");
}
};
}

int main()
{
std::map<int, int> m1;
std::map<int*, int> m2;

// OK, not a specialization
m1[0] = 42;
for (auto& keyval : m1)
{
(void)keyval;
}

m2[nullptr] = 42; // Insertion is OK
for (auto& keyval : m2) // static_assert failure
{
(void)keyval;
}
}

但是,

  • 我还没有想出一种方法来为自定义分配器扩展它:特化的声明必须依赖于某些用户定义的类型。
  • 这是一个糟糕的组合,所以我只会用它来查找现有案例(而不是作为静态检查器保留)。

关于c++ - 通过在迭代指针键映射上出错来捕获不确定性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57150993/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com