{"id":2050,"date":"2015-01-02T20:59:39","date_gmt":"2015-01-02T19:59:39","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=2050"},"modified":"2015-01-03T15:26:30","modified_gmt":"2015-01-03T14:26:30","slug":"raw-speed-of-c-using-oo-with-c-qt","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=2050","title":{"rendered":"raw speed of C using OO with C++"},"content":{"rendered":"<p>Programs written in C are very very fast. Those written in C++ can be slower due to the fact that copying object is not alway easy as copying an array of numbers. One have to call the copy constructor maybe with side effects like allocate some space. <\/p>\n<p>The language C++ is full backwards compatible to C. So what must we do to use classes and objects with the copy speed of C?<\/p>\n<p>First of all, in C there exist so called POD (plan old data) types like integers, floating point numbers as well as structs und unions. The C language have no class keyword. But classes in C++ can be POD too under certain circumstances. What exactly we need to get a class POD can be read in the C++11 Standard or under [1].<br \/>\nThe great benefit of POD types is that it can be copied by simply moving bytes in RAM from one location to another. No call to constructors is needed. That speed up copying enormously.<\/p>\n<p>Enough theory, lets build our own object oriented POD class!<br \/>\nLet's start with a simple class Point that represent a point in 2D. We want to construct a Point object by passing its x and y coordinate. We also want some getter and setter for the coordinates to make the member variables private.<\/p>\n<p>Here is our first implementation:<\/p>\n<pre><code>\r\n#include < iostream >\r\n#include < type_traits >\r\n\r\nclass Point {\r\npublic:\r\n  Point() : x(0), y(0) {}\r\n  Point(double x, double y) : x(x), y(y) {}\r\n\r\n  void setX(double x) { this->x = x; }\r\n  void setY(double y) { this->y = y; }\r\n  double getX() const { return x; }\r\n  double getY() const { return y; }\r\n\r\nprivate:\r\n  double x, y;\r\n};\r\n\r\nint main() {\r\n  Point p(1,2);\r\n  Point p2;\r\n\r\n  std::cout << p.getX() << \" \" << p.getY() << std::endl;\r\n\r\n  return 0;\r\n}\r\n<\/code><\/pre>\n<p>Pretty straight forward, right? Save it under point.cpp and compile it with:<\/p>\n<pre>\r\n$ g++-4.7 -Wall -Wextra -std=c++11 point.cpp \r\n$ .\/a.out \r\n1 2\r\n<\/pre>\n<p>I use as compiler gnu g++ version 4.7 to test backwards compatibility. Current is 4.9.2 and 5.0 will be released soon. But you can use any compiler as long it supports c++11. Except for g++ 4.6 thats too old.<\/p>\n<p>To test of a type id POD c++11 provides a simple test [2] which is defined in header file \"type_traits\". Add this line to our main() function, recompile and run again<\/p>\n<pre><code>\r\nstd::cout << std::boolalpha;\r\nstd::cout << \"Point is POD \" << std::is_pod<Point>::value << \"\\n\";\r\n<\/code><\/pre>\n<pre>\r\n$ g++-4.7 -Wall -Wextra -std=c++11 point.cpp \r\n$ .\/a.out\r\n1 2\r\nPoint is POD false\r\n<\/pre>\n<p>This shouldn't be too much surprising. As mentioned earlier there are strict rules for when a type is POD. For example the class must be a TrivialType [3]. We can test with is_trivial().<\/p>\n<pre><code>\r\nstd::cout << \"Point is TrivialType \" << std::is_trivial<Point>::value << \"\\n\";\r\n<\/code><\/pre>\n<pre>\r\n$ g++-4.7 -Wall -Wextra -std=c++11 point.cpp \r\n$ .\/a.out\r\n1 2\r\nPoint is POD false\r\nPoint is trivial false\r\n<\/pre>\n<p>A TrivialType in turn must be TriviallyCopyable [4] and must have Trivial default constructor [5]. Lets test these:<\/p>\n<pre><code>\r\nstd::cout << \"Point is TriviallyCopyable \" << std::is_trivially_copyable<Point>::value << \"\\n\";\r\nstd::cout << \"Point is trivially default-constructible \" << std::is_trivially_default_constructible<Point>::value << \"\\n\";\r\n<\/code><\/pre>\n<p>...<\/p>\n<p>Unfortunately g++ 4.9 does not implement these tests. So we have to wait for version 5.<br \/>\nInstead we can have a closer look about what a \"Trivial default constructor\" is. <\/p>\n<blockquote><p>\nThe default constructor for class T is trivial (i.e. performs no action) if all of the following is true:<\/p>\n<li>The constructor is not user-provided (that is, implicitly-defined or defaulted)<\/li>\n<li>T has no virtual member functions<\/li>\n<li>T has no virtual base classes <\/li>\n<li>T has no non-static members with brace-or-equal initializers<\/li>\n<li>Every direct base of T has a trivial default constructor<\/li>\n<li>Every non-static member of class type has a trivial default constructor<\/li>\n<\/blockquote>\n<p>Right the first condition does not hold. We provide a user default constructor which simply set x and y to zero. Lets remove this constructor and see whats happen:<\/p>\n<pre>\r\n$ g++-4.7 -Wall -Wextra -std=c++11 point.cpp \r\npoint.cpp: In function \u2018int main()\u2019:\r\npoint.cpp:20:9: error: no matching function for call to \u2018Point::Point()\u2019\r\npoint.cpp:20:9: note: candidates are:\r\npoint.cpp:7:3: note: Point::Point(double, double)\r\npoint.cpp:7:3: note:   candidate expects 2 arguments, 0 provided\r\npoint.cpp:4:7: note: constexpr Point::Point(const Point&)\r\npoint.cpp:4:7: note:   candidate expects 1 argument, 0 provided\r\npoint.cpp:4:7: note: constexpr Point::Point(Point&&)\r\npoint.cpp:4:7: note:   candidate expects 1 argument, 0 provided\r\n<\/pre>\n<p>It seems we don't have any default constructor anymore. Only the explicit user defined with two arguments and the implicit copy constructor. Thats right. That c++ standard say, that when a explicit user constructor is provided, the compiler don't have to create default constructors. <\/p>\n<p>With the new 2011 standard we can explicit request a implicit default constructor!<br \/>\nReplace this line with the following:<\/p>\n<pre><code>\r\nPoint() : x(0), y(0) {}\r\nPoint() = default;\r\n<\/code><\/pre>\n<pre>\r\n$ g++-4.7 -Wall -Wextra -std=c++11 point.cpp \r\n$ .\/a.out \r\n1 2\r\nPoint is POD true\r\nPoint is TrivialType true\r\n<\/pre>\n<p>Congratulations! We have a object oriented class that is as fast as old C style stuff.<\/p>\n<p>One important note: Variables in C are not automatic initialized! So our class Point is also not default initialized! See [6] for details. You have to call a constructor explicit e.g.<br \/>\n<code>Point p = Point();<\/code><\/p>\n<p>Here is some nice code to make sure your types are POD. If something goes wrong and the<br \/>\ntype is not POD, it gave an compiler error<\/p>\n<pre><code>\r\n#if __cplusplus >= 201103L\r\nstatic_assert(!std::is_polymorphic<Point>::value, \"Please do not add virtual functions to class Point!\");\r\nstatic_assert(std::is_pod<Point>::value, \"Class Point is not POD!\");\r\n#endif\r\n<\/code><\/pre>\n<p>The #if __cplusplus stuff is to check if the compiler has enabled c++11 standard.<br \/>\nDid you know that gnu g++ has set __cplusplus simply to 1 and this bug was know over 10 years?! The reason is very simple: If they fix it, they broke solaris 8. See [7]. Stupid non standard compliant solaris 8 code!<\/p>\n<p>You can download the example code here <a href=\"http:\/\/roboblog.fatal-fury.de\/wp-content\/uploads\/2015\/01\/point.cpp_.zip\">point.cpp.zip<\/a><\/p>\n<p>[1] http:\/\/en.cppreference.com\/w\/cpp\/concept\/PODType<br \/>\n[2] http:\/\/en.cppreference.com\/w\/cpp\/types\/is_pod<br \/>\n[3] http:\/\/en.cppreference.com\/w\/cpp\/concept\/TrivialType<br \/>\n[4] http:\/\/en.cppreference.com\/w\/cpp\/concept\/TriviallyCopyable<br \/>\n[5] http:\/\/en.cppreference.com\/w\/cpp\/language\/default_constructor<br \/>\n[6] http:\/\/en.cppreference.com\/w\/cpp\/language\/default_initialization<br \/>\n[7] https:\/\/gcc.gnu.org\/bugzilla\/show_bug.cgi?id=1773<\/p>\n<p>todo:<br \/>\n*Ich glaube ja nicht daran, dass das Vorhandensein eines Konstruktors den Code langsamer macht.<br \/>\n*Eine Sache, die ich unterstreichen w\u00fcrde, ist, dass in C++ \"harmlos\" aussehender Code sehr ineffizient sein kann<br \/>\n*F\u00fcr so eine Behauptung muss man schon vern\u00fcnftige Benchmarks zeigen<br \/>\n*C++-03 noch kein Moven ga<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Programs written in C are very very fast. Those written in C++ can be slower due to the fact that copying object is not alway easy as copying an array of numbers. One have to call the copy constructor maybe with side effects like allocate some space. The language C++ is full backwards compatible to [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[14,17,31],"class_list":["post-2050","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-c","tag-cpp","tag-faster-code"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/2050","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2050"}],"version-history":[{"count":14,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/2050\/revisions"}],"predecessor-version":[{"id":2072,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/2050\/revisions\/2072"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2050"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2050"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2050"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}