【问题标题】:Is there a way to disallow pointer comparison in C++?有没有办法在 C++ 中禁止指针比较?
【发布时间】:2014-11-04 05:46:11
【问题描述】:

我有一个(工作的)代码库,我想在其中添加类似 is_equivalent 成员的东西到类层次结构中。散布在整个代码库中的比较像

if (foo == bar) ...

其中foobar 是指向类层次结构中对象的普通指针。我想介绍如下用法(作为基类中的虚函数):

if (foo->is_equivalent(bar)) ...

这样“平等”的概念就被放宽了。一个具体的几何示例可能是一个形状层次结构,其中 Circle 应被视为等同于具有相同长轴和短轴的 Ellipse(不是完美的类比)。

我想做的是让编译器帮助我找到我进行直接指针比较的所有实例。我的一个想法是提供类似operator==(const Shape *, const Shape *) 的东西,但C++ 甚至不允许这样做。

有些指针比较可能需要保持指针比较,但有些则需要改为虚方法调用。我需要看看每一个。有什么方法可以识别所有这些类型的比较?暂时中断构建或执行都可以。有很好的测试覆盖率。

我已经阅读了类似的问题C++ Trick to avoid pointer comparison,但更有限,因为接受的答案假定存在工厂类。

【问题讨论】:

  • 您是否认为为此特定目的编写自定义静态分析工具并在您的代码库(可能定期)上运行它是一个可行的选择? libclang 有一个非常完整的 AST API - 我假设 - 您可以使用它来过滤所有指针比较。
  • @TheParamagneticCroissant:这是一个可行的想法,而且了解 libclang 本身也可能很有趣。
  • 你的问题的例子没有多大意义。 if (foo == bar) 正在比较对象 foo 是否与 bar 相同 - 这与 char *foo = "abc"; char bar[] = "abc"; if (foo == bar) 相同 - 这不是真的,因为 foobar 指向不同的内存位.如果你比较if (*foo == *bar),那么你绝对可以通过实现operator==在C++中做你想做的事情。
  • @MatsPetersson 这正是 Greg 想要避免的(IMO 潜在错误的、误导性的)指针比较。我相信他很清楚对象上重载的== 运算符和比较指针的== 运算符之间的区别。
  • 你知道,有很多不同的编码方式。我不是在要求额外的策略来避免我目前遇到的问题。我正在寻求策略来帮助我摆脱我所处的情况。

标签: c++ pointers equality


【解决方案1】:

您可以编写自定义代码分析工具。这是我使用libclang 构建的一个最小(而且相当简单)的示例。这会过滤掉源中的每个二元运算符。通过改进这一点,您可以从 AST 中收集所有指针相等比较。

#include <clang-c/Index.h>
#include <stdio.h>

static void printBinOp(CXCursor cursor)
{
    CXSourceRange range = clang_getCursorExtent(cursor);
    CXSourceLocation begin = clang_getRangeStart(range);
    CXSourceLocation end = clang_getRangeEnd(range);
    CXFile file;
    unsigned begin_offset, end_offset, length;

    // retrieve physical location of AST node
    clang_getSpellingLocation(begin, &file, NULL, NULL, &begin_offset);
    clang_getSpellingLocation(end, NULL, NULL, NULL, &end_offset);
    length = end_offset - begin_offset;

    // Open the file, error checking omitted for clarity
    CXString xfname = clang_getFileName(file);
    const char *fname = clang_getCString(xfname);
    FILE *fhndl = fopen(fname, "r");
    clang_disposeString(xfname);

    // Read the source
    char buf[length + 1];
    fseek(fhndl, begin_offset, SEEK_SET);
    fread(buf, length, 1, fhndl);
    buf[length] = 0;
    fclose(fhndl);

    // and print it
    printf("Comparison: %s\n", buf);
}

static enum CXChildVisitResult ptrCompVisitor(CXCursor cursor, CXCursor parent, CXClientData client_data)
{
    if (clang_getCursorKind(cursor) == CXCursor_BinaryOperator) {
        printBinOp(cursor);
    }

    return CXChildVisit_Recurse;
}

int main()
{
    CXIndex index = clang_createIndex(0, 0);
    CXTranslationUnit tu = clang_parseTranslationUnit(index, "foo.cpp", NULL, 0, NULL, 0, CXTranslationUnit_None);

    clang_visitChildren(clang_getTranslationUnitCursor(tu), ptrCompVisitor, NULL);

    clang_disposeTranslationUnit(tu);
    clang_disposeIndex(index);
    return 0;
}

我使用的示例文件是这个虚构的 C++ 源文件(名为 foo.cpp):

class Foo {
    int foo;
};

class Bar {
    int bar;
}

int main()
{
    void *f = new Foo();
    void *b = new Bar();

    bool alwaystrue_1 = f == f;
    bool alwaystrue_2 = b == b;

    return f == b;
}

我的工具为此打印了这个:

Comparison: f == f
Comparison: b == b
Comparison: f == b

【讨论】:

  • 谢谢,这看起来是个不错的起点!
猜你喜欢
  • 2020-05-10
  • 1970-01-01
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多