943,910 Members | Top Members by Rank

Ad:
  • C++ Discussion Thread
  • Unsolved
  • Views: 2875
  • C++ RSS
Apr 5th, 2005
0

C++ tips

Expand Post »
This is a short list of recommendations on how to use C++. My experiences are from using gcc 2.8.0 and Visual C++ 6.0. I had to have things compatible between these two compilers, and between Unix and Windows.

Contents

IO of binary files

When are destructors called for local variables

Use {} to keep things local

Scope of variables declared in for()

When to use virtual members



IO of binary files

To make sure that there is no CR/LF translation on non-Unix computers, you have to use the following lines to open streams to files with binary data.




C++ Syntax (Toggle Plain Text)
  1. ofstream os("output.flt", ios::out | ios::binary);
  2.  
  3.  
  4.  
  5. ifstream is("output.flt", ios::in | ios::binary);
For Visual C++, when using fstream.h, use in addition the flag ios::nocreate. Otherwise you can open a non-existing file for reading, without complaining. (This is not necessary when using fstream).




When are destructors called for local variables



Non-static (or 'automatic' ) variables are 'destructed' automatically when they go out of scope. Scope is a farily complicated thing, and I'm not going to repeat the definition here. Roughly speaking the scope ends when you encounter the } around the declaration of the variable. See also the use of {} and how scope is defined in the for() statement.

Variables are destructed (by the compiler) by calling the appropriate destructor of their class. If the objects allocate memory (and hence the destructor should free that memory), this means that you recover the memory allocated.


C++ Syntax (Toggle Plain Text)
  1.  
  2.  
  3.  
  4. class array
  5. {
  6. private:
  7. float *ptr;
  8. public:
  9. // constructor
  10. array(int n) { ptr = new float[n]; }
  11. // destructor
  12. ~array() { delete [] ptr; }
  13. }
  14.  
  15. main()
  16. {
  17. // ...
  18. {
  19. array a(5); // allocates memory
  20. // do something
  21. }
  22. // here the array is destructed, and so the memory is freed
  23. //....
  24. }






Use {} to keep things local





Use of the grouping construct {} enables you to declare variables local to that group. When leaving the group, all local variables are destructed. This has the advantage that the reader of the code knows (s)he shouldn't worry about these variables to understand the rest of the code.
In a way this can be understood as if every use of {} is like a function call (with local variables declared in the function). Of course, you don't have the overhead of stack manipulations and jumps involved in a proper function call.






C++ Syntax (Toggle Plain Text)
  1. // recommended usage<blockquote>
  2.  
  3.  
  4.  
  5.  
  6.  
  7. void f(int a)
  8. {
  9. if(a==1)
  10. {
  11. myclassA Aobject;
  12. // here I do something with 'Aobject', and maybe 'b'
  13. }
  14. // Aobject does not exist here anymore
  15. }
  16. </blockquote>




This tip is just an extension of the 'avoid global variables' credo.



As always, this can be disabused as in the following piece of code, where the outer variable 'a' is hidden by a local 'a', resulting in not very readable code.





C++ Syntax (Toggle Plain Text)
  1. // not very readable code<blockquote>
  2.  
  3.  
  4.  
  5.  
  6.  
  7. {
  8. int a=1;
  9. {
  10. // local variable hides outer 'a'
  11. int a;
  12. a = 2;
  13. assert (a==2);
  14. }
  15. // a is again the previous variable
  16. assert (a==1);
  17.  
  18. }</blockquote>




Scope of variables declared in for()



The new ANSI C++ standard specifies that variables declared as in for(int i=1; ...) have a scope local to the for statement. Unfortunately, older compilers (for instance Visual C++ 5.0) use the older concept that the scope is the enclosing group. Below I list 2 possible problems, and their recommended solutions:
  • you want to use the variable after the for() statement
you have to declare the variable outside of the for() statement.







C++ Syntax (Toggle Plain Text)
  1. int i;
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8. for(i=1; i<5; i++)
  9. { /* do something */ }
  10. if (i==5) ...





  • you want to have multiple for() loops with the same variables.
Put the for statement in its own group. You could also declare the variable outside of the 'for', but it makes it slightly trickier for an optimising compiler (and a human) to know what you intend.




C++ Syntax (Toggle Plain Text)
  1. {
  2.  
  3.  
  4.  
  5.  
  6.  
  7. for(i=1; i<5; i++)
  8. { /* do something */ }
  9. }





When to use virtual members




Make a member 'virtual' if a derived class extends the functionality of a member of the base class, and this extended functionality has to be accessible:
  1. inside other member functions of the base class
  2. when using pointers that can point to either an object of the base class, or an object of the derived class.
Example: multi-dimensional arrays which are defined recursively in terms of a 1D array.
We wanted to have a 'grow' member that enlarged the outer dimension of the multidimensional array. At first sight, this is simply calling a general grow of the base class. However, 'grow' has to know the size of the new elements (which are again multidimensional arrays). So, we had to define in the derived class a new 'grow', which calls the base class 'grow' first, and then does more stuff.
At many points in the base class, 'grow' is called to adjust sizes. By making 'grow' virtual we avoid to having to rewrite these members for the derived class.

Caveat:

For members of the base class which use temporary objects of its own type, the base class 'grow' will be called. For instance:




C++ Syntax (Toggle Plain Text)
  1. class array
  2.  
  3.  
  4.  
  5.  
  6.  
  7. {
  8. ...
  9. virtual void grow(int new_size);
  10.  
  11. array& operator +=( const array& a)
  12. { /* some definition using 'grow' */ }
  13. array operator +(const array& a1, const array& a2)
  14. {
  15. array a=a1;
  16. a += a2;
  17. // Warning, this will call array::grow, even if a1 is really from a derived type
  18. }
  19. };




Thus, you should provide a member of the derived class for every member of the base class which uses temporary objects.




C++ Syntax (Toggle Plain Text)
  1. <blockquote>class multiarray : public array
  2.  
  3.  
  4.  
  5.  
  6.  
  7. {
  8. ...
  9. virtual void grow(int new_size);
  10.  
  11. multiarray operator +(const multiarray& a1, const multiarray& a2)
  12. {
  13. multiarray a=a1;
  14. a += a2;
  15. }
  16. };
  17.  
  18.  
  19.  
  20.  
  21. </blockquote>
Similar Threads
Team Colleague
Reputation Points: 55
Solved Threads: 3
Junior Poster
meabed is offline Offline
139 posts
since May 2004

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in C++ Forum Timeline: I am trying to get this code to work. Please help.
Next Thread in C++ Forum Timeline: 1700+ ebooks on programming





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC