![](/img/trans.png)
[英]SWIG-generated Lua<-->C++ Wrapper mishandling primitive types renamed by typedef
[英]Performance: typedef vs wrapper class for primitive types?
我想在C ++中定義一個新類型,它只是一些原始類型(在我的例子中是一個int
,可以是任何類型)。 我在這個例子中調用了NodeId
類型。
我可以使用typedef int NodeId
。 我想要一個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;}
//...
};
是否存在導致使用第二種方法的性能缺點?
實際上,有兩個原因可以想象這會慢一些。
首先,沒有辦法創建一個未初始化的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);
如果使用相對較新的編譯器,則生成的代碼應該相同。 編譯器應該沒有內聯這些成員函數的問題。 如果您對此有疑問,可以隨時反匯編可執行文件。
如果編譯器優化設置允許編譯器內聯所有內容,則應該沒有性能差異。 我能發現的唯一缺點是基於此類對象的表達式可能不再符合編譯時常量,這在模板編程中可能很重要。 除此之外,您最終可以獲得額外的清晰度,而無需運行時間。
operator int
和isValid
中缺少const
:
inline operator int() const {return value;} inline bool isValid() const {return value != -1;}
如果你打算將它變成一個可能被其他編程語言使用的庫(比如你將它寫入C ++ DLL),那么將它設置為typedef int
有一定的優勢。
例如,當你為你的API編寫python包裝器或java包裝器時,你沒有那么頭疼讓你的類和類型被移植。 那么你要擔心的是int
的位大小。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.