7

我想在 C++ 中定义一个新类型,它只是一些原始类型(在我的示例中,一个int, 可以是任何类型)。NodeId我在这个例子中调用类型。

我可以只使用typedef int NodeId. 我想要 s 的默认值NodeId,所以我会使用#define NULL_NODE_ID -1.

typedef现在,我认为定义一个类而不是允许一个函数isValid()和一个默认构造函数构造一个 null会更好NodeId

class NodeId
{
    int value;
public:
    inline NodeId() : value(-1) {}
    inline NodeId(int value) : value(value) {}
    inline operator int() {return value;}
    inline bool isValid() {return value != -1;}
    //...
};

是否存在导致使用第二种方法的性能劣势?

4

4 回答 4

6

实际上,这可能会变慢有两个原因。

首先,无法创建未初始化的 NodeId。通常,这是一件好事。但是想象一下你有这样的代码:

NodeId nodeid;
foo.initializeNodeId(&nodeid);

你会做一个实际上没有必要的额外任务。

您可以通过添加一个特殊的构造函数来解决这个问题。创建一个 Foo::createNodeId() 可能要好得多,这样你就不需要 Foo::initializeNodeId(&NodeId),但如果你不控制 Foo 的定义,那可能是不可能的。

其次,NodeId 不是编译时常量表达式。正如 dasblinkenlight 所暗示的,这更可能导致代码不合法​​而不是导致性能问题,但两者都有可能。(为什么?因为您可能会强制编译器在运行时插入代码来执行一些计算,如果您使用的是 int,那么这可能在编译时完成。这对于名为 NodeId 的类来说可能不是问题...... )

幸运的是,如果您使用的是 C++11,则可以使用 constexpr 修复它。如果你希望你的代码也是合法的 C++03,你可以用一个宏来处理它。

此外,正如 dasblinkenlight 所指出的,您在两种方法中都缺少 const 。

最后,没有理由在类定义中定义的方法上写“内联”;它们本身就已经是内联的了。

把它们放在一起:

#if __cplusplus > 201000L
#define CONSTEXPR_ constexpr
#else
#define CONSTEXPR_
#endif

class NodeId
{
    int value;
public:
    struct Uninitialized {};
    CONSTEXPR_ NodeId() : value(-1) {}
    CONSTEXPR_ NodeId(Uninitialized) {}      
    CONSTEXPR_ NodeId(int value) : value(value) {}
    CONSTEXPR_ operator int() const {return value;}
    CONSTEXPR_ bool isValid() const {return value != -1;}
    //...
};

现在您可以这样做,以避免额外的 -1 分配成本。

NodeId nodeId(NodeId::Uninitialized());
foo.initializeNodeId(&nodeid);

并且,为了合法地使用 NodeId 作为非类型模板参数:

myClassTemplate<NodeId(3)> c;

或者,为了确保编译器可以合法地将 x 初始化为 4:

int x = 3;
x += NodeId(1);
于 2012-07-03T22:47:04.930 回答
4

如果您使用相对较新的编译器,那么生成的代码应该是相同的。编译器内联这些成员函数应该没有问题。如果您真的对此有疑问,您可以随时反汇编可执行文件。

于 2012-07-03T22:24:46.060 回答
3

如果编译器优化设置让编译器内联所有内容,那么应该没有性能差异。我能发现的唯一缺点是基于此类对象的表达式可能不再符合编译时常量的条件,这在模板编程中可能很重要。除此之外,您最终会获得额外的清晰度,而无需运行时成本。


constPS您在operator intand 中缺少isValid

inline operator int() const {return value;}
inline bool isValid() const {return value != -1;}
于 2012-07-03T22:28:02.593 回答
1

如果你打算把它做成一个库,可以被其他一些编程语言使用(比如如果你把它写成一个 C++ DLL),那么拥有一个typedef int.

例如,当您为 API 编写 python 包装器或 java 包装器时,将类和类型移植过来就不会那么头疼了。那么你只需要担心int.

于 2012-07-03T22:54:51.027 回答