29 | | |
| 29 | |
| 30 | == const and const& == |
| 31 | Given the following example: |
| 32 | {{{ |
| 33 | class MyClass |
| 34 | { |
| 35 | public: |
| 36 | void setPosition(Vector3 position) { this->myPosition_ = position; } |
| 37 | Vector3 getPosition() { return this->myPosition_; } |
| 38 | private: |
| 39 | Vector3 myPosition_; |
| 40 | }; |
| 41 | }}} |
| 42 | And you execute the following code: |
| 43 | {{{ |
| 44 | MyClass obj1, obj2; |
| 45 | Vector3 pos(10, 20, 30); |
| 46 | |
| 47 | obj1->setPosition(pos); |
| 48 | obj2->setPosition(obj1->getPosition()); |
| 49 | }}} |
| 50 | In this example, a lot of overhead is executed, because Vector3 pos is not only created once, but in fact 4 times. The red parts of the code create a new instance of Vector3: |
| 51 | {{{ |
| 52 | #!html |
| 53 | <pre class="wiki"> |
| 54 | void setPosition(<span style="color:#FF0000;">Vector3 position</span>) { this->myPosition_ = position; } |
| 55 | <span style="color:#FF0000;">Vector3</span> getPosition() { return this->myPosition_; } |
| 56 | </pre> |
| 57 | }}} |
| 58 | By calling 2 times setPosition and once getPosition, we create 3 additional instances of Vector3. This overhead can be reduced by using constant references: |
| 59 | {{{ |
| 60 | #!html |
| 61 | <pre class="wiki"> |
| 62 | void setPosition(<span style="color:#00AA00;">const Vector3& position</span>) { this->myPosition_ = position; } |
| 63 | <span style="color:#00AA00;">const Vector3&</span> getPosition() { return this->myPosition_; } |
| 64 | </pre> |
| 65 | }}} |
| 66 | The rest of the code remains the same. |
| 67 | |
| 68 | Now you may think of a situation, where OtherClass has a MyClass as a membervalue: |
| 69 | {{{ |
| 70 | class OtherClass |
| 71 | { |
| 72 | public: |
| 73 | void setObject(const MyClass& object) { this->object_ = object; } |
| 74 | const MyClass& getObject() { return this->object_; } |
| 75 | |
| 76 | private: |
| 77 | MyClass object_; |
| 78 | }; |
| 79 | }}} |
| 80 | And you want to execute the following code: |
| 81 | {{{ |
| 82 | OtherClass instance; |
| 83 | Vector3 position = instance.getObject().getPosition(); |
| 84 | }}} |
| 85 | But this doesn't work. Why? Because OtherClass returns a '''const''' reference to MyClass. This means, you can't change anything in MyClass. But getPosition() doesn't change anything? You're absolutely right, but the compiler doesn't know about that. You have to tell him by adding the const keyword to the function head as well: |
| 86 | {{{ |
| 87 | #!html |
| 88 | <pre class="wiki"> |
| 89 | const Vector3& getPosition() <span style="color:#00AA00;">const</span> { return this->myPosition_; } |
| 90 | </pre> |
| 91 | }}} |
| 92 | And we better do the same for OtherClass::getObject as well: |
| 93 | {{{ |
| 94 | #!html |
| 95 | <pre class="wiki"> |
| 96 | const MyClass& getObject() <span style="color:#00AA00;">const</span> { return this->object_; } |
| 97 | </pre> |
| 98 | }}} |
| 99 | Now the code from above will compile without problem. |
| 100 | |
| 101 | So please remember the following rules: |
| 102 | * Alway use '''const&''' if you got an existing instance of the object you want to pass |
| 103 | * Only create a new instance in a return value if you return a temporary object |
| 104 | * Add '''const''' to all functions that don't change the class. |
| 105 | |
| 106 | And remember: '''const ObjectName&''' might look scary, but it's your friend. ;) |
| 107 | |
76 | | Object* obj = new Object*(); /* this is only a local reference! automatically deleted after function return */ |
77 | | SomeClass* sc = new SomeClass(); /* creation of a new object needs much time, avoid it if possible - here we need it */ |
78 | | sc->wantObjectReference(obj); |
79 | | delete sc; /* remember that creating and deleting object need VERY much time*/ |
80 | | } |
81 | | }}} |
| 152 | Object* obj = new Object*(); /* now the object is created with 'new' and won't be deleted after function return */ |
| 153 | sc->wantObjectReference(obj); |
| 154 | } |
| 155 | }}} |
| 156 | Of course SomeClass must now delete the object reference if it isn't needed anymore. |
96 | | Now what's wrong here is the local variable. When the temporary object is made on the first line, the constructor is called and the object initialized. But we didn't want that to happen! We assign new values anyways in the next lines. Always keep in mind the time wasted when creating objects. [br] |
97 | | The copy constructor is called again in the end of the function, as returnVector is a local variable. This just shows why this style is very bad. [br] |
98 | | A problem which lies hidden is the problem of parameter. As the parameter is a copy of the original argument, we get another useless object construction. [br] |
| 171 | Now what's wrong here is the local variable. When the temporary object is made on the first line, the constructor is called and the object initialized. But we didn't want that to happen! We assign new values anyways in the next lines. Always keep in mind the time wasted when creating objects. [[br]] |
| 172 | The copy constructor is called again in the end of the function, as returnVector is a local variable. This just shows why this style is very bad. [[br]] |
| 173 | A problem which lies hidden is the problem of parameter. As the parameter is a copy of the original argument, we get another useless object construction. [[br]] |