在MyClass指针的容器中找到空指针?

时间:2019-01-05 18:05:09

标签: c++ casting undefined-behavior void-pointers

我有一个指向未知类型变量的指针void* p,还有一个装有std::set<MyClass*> c指针的容器MyClass。是否有某种方法可以找出c是否包含p(即是否包含一个指向与p相同的内存地址的指针)而无需手动循环访问{{1 }},这不会导致未定义的行为吗? (请注意,如果我在c中找不到p,就不会取消引用。)

此外,我假设如果c指向与p不相关的数据类型的变量,则将MyClass*强制转换为p会导致未定义的行为,但是也许不是这样吗?

3 个答案:

答案 0 :(得分:1)

您可以安全地将void*强制转换为另一个指针,但不要取消引用它。在std::set<T*>中查找指针不会取消引用该指针(除非您指定一个这样做的自定义比较谓词)。

根据C ++标准,目前看来,仅加载无效的指针是未定义的行为。但是,这是使用segmented addressing(x86实模式)的硬件体系结构的一种规定,其中加载指针会将其值的一部分加载到段寄存器中,这可能会导致硬件陷阱。在具有平面内存模型的现代体系结构中,此限制不适用,加载任何指针值的定义都很好,因为这只是加载到通用CPU寄存器中。

类似的东西:

MyClass* find(std::set<MyClass*> const& c, void* p) {
    auto found = c.find(static_cast<MyClass*>(p));
    return found != c.end() ? *found : nullptr;
}

您可以像这样使用它:

std::set<MyClass*> c;
void* p = ...;
if(MyClass* q = find(c, p))
   // p is found and is q

答案 1 :(得分:1)

  

我假设如果[..]

,将p强制转换为MyClass*会导致未定义的行为

从理论上讲,它可能会导致UB。

但是可能应该在实践中起作用(UB的乔伊)。

  

是否有某种方法可以找出c是否包含p [..],而无需手动循环访问c中的元素。

std::find_ifstd::binary_search可以与适当的谓词一起使用以在线性时间内找到它(std::set::iterator不是随机迭代器,因此“伪造” binary_search的复杂性)。

如果您可以将容器更改为:

  • std::set<MyClass*, std::less<void>>,那么您可以安全地使用std::set::find 感谢透明的比较器。

  • std::vector<MyClass*>进行了排序,那么您可能会以正确的复杂性使用std::binary_search

答案 2 :(得分:0)

在实践中,您应该能够做到(请参阅其他分析工具和评论),但是您需要注意一些陷阱。

如果您有从另一个类(例如OtherClass)和MyClass派生的类,则需要确保p指向MyClass部分而不是{{ 1}}。虽然您不会有未定义的行为,但是找不到该项目。

OtherClass

在这种情况下,您不会在集合中找到class OtherClass { int someData; }; class WontWork : public OtherClass, public MyClass { }; auto *w = new WontWork(); c.insert(w); void *p = w; ,因为p的值不同于插入到集合中的值(在隐式转换为p之后)。

要使代码正常工作,您需要执行以下操作来使MyClass *指向p部分:

MyClass

void *p = static_cast<MyClass *>(w);

但是,然后,必须确保不要在代码中的其他位置使用MyClass *mc = w; p = mc; p类型的OtherClass

如果可能的话,最好通过修正声明来完全避免使用WontWork