Sign in to follow this  
Niux

C++ best practices (specific examples)

Recommended Posts

Hey all I'm in the process of learning C++ and I have a few questions about how to do some specific stuff the right way. 1. Which is the better solution and why?
//somewhere an object is defined
MyClass t = MyClass(...);

//here's functions that operates on MyClass
void doStuffWithTable1(MyClass* t) {
   ...
   ...
}

// OR

void doStuffWithTable2(MyClass& t) {
   ...
   ...
}

2. Will this work? Why not and how to do it right?
//foo.h
...
std:vector<MyClass> classes;
...

//foo.cpp
...
Foo::Foo() {
   for(int i = 0; i < n; i++) {
       MyClass t(...);
       //do stuff with t
       classes.push_back(t);
   }
}
...

Will classes after this for-loop, contain n instances of MyClass?

Share this post


Link to post
Share on other sites
1. First solution lets you pass NULL, second one does not, because a reference is just another name for an already existing object, so doStuffWithTable1 has to check, if a valid instance has been passed, while doStuffWithTable2 can safely assume the paramter is valid

2. Yep, I'm pretty sure this will work, but why don't you try it out yourself?

Share this post


Link to post
Share on other sites
1) Use references instead of pointers when you can. They're (almost) guaranteed to be valid. Use pointers when you need the ability to pass NULL. Also, use const MyClass* and const MyClass& if you don't want to change the parameter inside the function.

2) Sure, why not? As long as MyClass copies correctly, that code should be fine.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ariste
1) Use references instead of pointers when you can. They're (almost) guaranteed to be valid. Use pointers when you need the ability to pass NULL. Also, use const MyClass* and const MyClass& if you don't want to change the parameter inside the function.

2) Sure, why not? As long as MyClass copies correctly, that code should be fine.


IIRC const MyClass * was trickier, was not something like const MyClass *const varName?

Share this post


Link to post
Share on other sites
Quote:
Original post by Gammenon
Quote:
Original post by Ariste
1) Use references instead of pointers when you can. They're (almost) guaranteed to be valid. Use pointers when you need the ability to pass NULL. Also, use const MyClass* and const MyClass& if you don't want to change the parameter inside the function.

2) Sure, why not? As long as MyClass copies correctly, that code should be fine.


IIRC const MyClass * was trickier, was not something like const MyClass *const varName?


No.

const T* is a pointer to const T. You can change the pointer (to point to a different object, to null) but not the pointee.

const T* const is a const pointer to const T. You can change neither the pointer nor the pointee.

const T* const is roughly equivalent to const T&.

Share this post


Link to post
Share on other sites
Quote:
Original post by TheUnbeliever
Quote:
Original post by Gammenon
Quote:
Original post by Ariste
1) Use references instead of pointers when you can. They're (almost) guaranteed to be valid. Use pointers when you need the ability to pass NULL. Also, use const MyClass* and const MyClass& if you don't want to change the parameter inside the function.

2) Sure, why not? As long as MyClass copies correctly, that code should be fine.


IIRC const MyClass * was trickier, was not something like const MyClass *const varName?


No.

const T* is a pointer to const T. You can change the pointer (to point to a different object, to null) but not the pointee.

const T* const is a const pointer to const T. You can change neither the pointer nor the pointee.

const T* const is roughly equivalent to const T&.



If I have a const T*, I can call some not-const function, but with const & I cannot. Am I wrong?

Share this post


Link to post
Share on other sites
Quote:
Original post by Gammenon
Quote:
Original post by TheUnbeliever
<snip>
No.

const T* is a pointer to const T. You can change the pointer (to point to a different object, to null) but not the pointee.

const T* const is a const pointer to const T. You can change neither the pointer nor the pointee.

const T* const is roughly equivalent to const T&.



If I have a const T*, I can call some not-const function, but with const & I cannot. Am I wrong?


I'm afraid so - you still have a const T as the pointee, so dereferencing the pointer allows you to do everything that you could do with a straight instance of (or reference to) const T but no more. So you can't modify it or call non-const member functions.

Share this post


Link to post
Share on other sites
Quote:
Original post by Niux
1. Which is the better solution and why?


Use references when you can, and pointers when you have to.

The same goes for any conceivable thing that you could use instead of the pointer.

However, also consider implementing this as a member function:


void MyClass::doStuffWith() {
...
...
}


Quote:

2. Will this work? Why not and how to do it right?


Do not define global variables in a header. You should declare them there, with 'extern', only if other source files will need to access them. Define the variable in the .cpp file.

Oh, you meant that 'classes' is a member of 'Foo'? Sure, that works fine then.

Quote:
Will classes after this for-loop, contain n instances of MyClass?


Yes; that's what .push_back() is for.

However, do you really need to "do stuff with t" before putting it into the vector? What is "stuff" here?

Share this post


Link to post
Share on other sites
Thanks for all the replies!

Quote:

Yes; that's what .push_back() is for.


Maybe I should have bin more specific in my question, however what I wanted to find out, was whether .push_back() would only put the reference in the vector and not copy the object. Meaning when the
Myclass t(...)
would go out of scope and be deleted, the reference would be invalid. But I probably should have thought about it one extra time, before asking, since classes is a vector of MyClass and not MyClass references.

Quote:

However, do you really need to "do stuff with t" before putting it into the vector? What is "stuff" here?


"Stuff" in this case is to initialize a member of MyClass with a random number. Now, this could be done in a constructor, but it is not really coherent with the class interface - using a setter method would be better in this case.

Another question I have;
When declaring members in the header file like this:

class MyClass {
public:
MyClass();
virtual ~MyClass();
private:
MyOtherClass o;
};



I noticed that the default (MyOtherClass(void)) constructor is automatically called. I looked it up and it is an error not to initialise the object when declared, thus the automatic call to the default constructor. BUT what I want, and this is most likely a Java ting I shouldn't be doing in C++, is to just declare the member object (o), and later initialise it:

o = MyOtherClass(...);

The reason for initialising it later could be that the constructor arguments are not calculated when the header is loaded. So the question is what is the correct C++ way to do this ? Right now I just have a default constructor that does nothing and then later reassign the member variable.

Share this post


Link to post
Share on other sites
Quote:
Original post by Niux
what I wanted to find out, was whether .push_back() would only put the reference in the vector and not copy the object.

Whatever you give to push_back will be copied into the vector via the copy constructor.

Quote:
Original post by Niux
since classes is a vector of MyClass and not MyClass references.

Note that there is no such thing as a vector of references. You probably meant a vector of pointers.

Quote:
Original post by Niux
I noticed that the default (MyOtherClass(void)) constructor is automatically called.

Only if you don't initialize yourself in the initialization list:

MyClass() : o(...) // <--- initialization list
{
// constructor body
}

Share this post


Link to post
Share on other sites
Quote:

Only if you don't initialize yourself in the initialization list:

MyClass() : o(...) // <--- initialization list

{

// constructor body

}



Aha! And I can have an initialization list for every constructor?

Can I use an argument to the constructor in the initialization list?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this