性能:typedef vs原始类型的包装类?

时间:2012-07-03 22:20:07

标签: c++ inline micro-optimization

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

我可以使用typedef int NodeId。我想要NodeId s的默认值,所以我会使用#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 个答案:

答案 0 :(得分: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);

答案 1 :(得分:4)

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

答案 2 :(得分:3)

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

<小时/> 附:您在constoperator int

中遗漏了isValid
inline operator int() const {return value;}
inline bool isValid() const {return value != -1;}

答案 3 :(得分:1)

如果你打算将它变成一个可能被其他编程语言使用的库(比如你将它写入C ++ DLL),那么使它成为typedef int会有明显的优势。

例如,当您为API编写python包装器或java包装器时,您没有太多头痛让您的类和类型移植到端口。然后你要担心的是int的位大小。