Sign in to follow this  
zyrolasting

C++ fundamentals I still have trouble with

Recommended Posts

zyrolasting    280
I'm having difficulty understanding a few keyword concepts. with const, what use can it have when it's put before a return type or a parameter? What does try/catch do, exactly? How does it differ from trying to catch an error with a simple condition? For that matter, some people use a '...' in some catch statements. What does that do? (The second part to this I am trying to Google, still would like to know concept though.) For what reason would someone want to make a do-nothing virtual destructor, or a few virtual functions when there are no classes to inherit them? (Both I have witnessed)

Share this post


Link to post
Share on other sites
Driv3MeFar    1080
Quote:
Original post by zyrolasting
with const, what use can it have when it's put before a return type or a parameter?


A const variable is a constant; it cannot be changed once initialized.

Quote:

What does try/catch do, exactly? How does it differ from trying to catch an error with a simple condition? For that matter, some people use a '...' in some catch statements. What does that do? (The second part to this I am trying to Google, still would like to know concept though.)


Try/catch blocks are used for exception handling. Basically, if you have a block of code that can throw an exception, wrap it in a try/catch block. What you put in the parenthesis of a catch() is the type of exception you want to catch, by putting (...), that catch block will handle anything that gets thrown.

Quote:

For what reason would someone want to make a do-nothing virtual destructor, or a few virtual functions when there are no classes to inherit them? (Both I have witnessed)


Base classes need virtual destructors to ensure that if an instance of a derived class is deleted from a base class pointer, the correct destructor will be called. Since default destructors are not virtual, you need to create an empty one.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by zyrolasting
with const, what use can it have when it's put before a return type or a parameter?


If you pass or return a value, it's useless.
If you pass a reference, 'const' means that the function promises not to alter the referred-to thing via that reference.
If you return a reference 'const' requires that the caller not alter the referred-to thing via the returned reference. (Note that it's easy to assign the returned reference to a value, which thus makes a copy which the caller can modify, and modifications to which do not affect what the function referred to.)

Quote:
What does try/catch do, exactly? How does it differ from trying to catch an error with a simple condition?


I don't know what you think you mean here, given that you use "try" and "catch" in your description of the alternative to try/catch. o_O Show some code.

Quote:
For that matter, some people use a '...' in some catch statements. What does that do? (The second part to this I am trying to Google, still would like to know concept though.)


Good luck with Googling that kind of thing; Google tends to ignore punctuation. :)

When you 'catch', you must specify what kind of thing to catch. It's usual to throw (and therefore catch) instances of classes (i.e. objects), but it's legal to throw any kind of data - including ints, string literals etc. There's no description that really covers any of those types, so C++ allows you to write "catch (...)" to mean catch anything. Of course, this means that you don't get to inspect the caught value, because you don't know what type it is, and it doesn't have a name.

Quote:
For what reason would someone want to make a do-nothing virtual destructor


When 'delete' is called on a base class pointer, the destructor is called. This is not fundamentally different from a normal function call: if the base class function is 'virtual', then dynamic dispatch is done; otherwise, the base class version of the function is used regardless.

If the function were not 'virtual', then the base class destructor would be called even if the pointer actually pointed at an instance of the derived class. This leads to undefined behaviour, technically. (In practice, it usually only results in memory leaks, if anything; but it costs nothing to get it right, because the compiler is very good at optimizing out do-nothing functions.)

Quote:
or a few virtual functions when there are no classes to inherit them? (Both I have witnessed)


There might not be such classes yet, but they might be planned for. Or maybe they simply weren't shown to you. It's also possible that the programmer was making a premature generalization. It's hard to say without seeing an actual example.

Share this post


Link to post
Share on other sites
bobofjoe    322
Quote:
Original post by Zahlman
Quote:
Original post by zyrolasting
with const, what use can it have when it's put before a return type or a parameter?


If you pass or return a value, it's useless.


Sometimes, returning a const value isn't completely useless. You can use it to stop people from doing things like ( foo + bar ) = baz; where foo overloads operator+ to return a constant value. Though, I admit, this is a very rare case, and is one of the very few reasons that you would want to return a constant value.

Share this post


Link to post
Share on other sites
Gage64    1235
Quote:
Original post by Zahlman
Quote:
Original post by zyrolasting
with const, what use can it have when it's put before a return type or a parameter?

If you pass or return a value, it's useless.


I'm not sure I agree.

In general, you mark a parameter as const when you don't want it to be changed inside a function. Now, it's true that if the parameter was passed by value, changing it would not affect the original variable, but if the function should not change the parameter, it's still a logical error. Marking the parameter as const allows the compiler to catch these errors.

Share this post


Link to post
Share on other sites
JimmyDeemo    156
Quote:
Original post by zyrolasting
with const, what use can it have when it's put before a return type or a parameter?


It can be useful when enforcing proper use of you created types. Let say you overloaded the * operator;


Widget operator*(const Widget& lhs, const Widget& rhs)
{
//Stuff
}



With the above code, something like this will compile;


Widget a,b,c;
//Do stuff
//...
a * b = c;



Not sure why you'd want to make an assignment to the product of two types. But its easily done by mistake.


if( a*b = c ) //Oh dear meant '=='



Defining the operator with a const return type will stop that compiling.


const Widget operator*(const Widget& lhs, const Widget& rhs)
{
//Stuff
}



Most of the above was summerised from 'Effective C++' by Scott Meyers. It might be a good read for you if want some more insight into how to use c++ better.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by bobofjoe
Sometimes, returning a const value isn't completely useless. You can use it to stop people from doing things like ( foo + bar ) = baz; where foo overloads operator+ to return a constant value. Though, I admit, this is a very rare case, and is one of the very few reasons that you would want to return a constant value.


I'm pretty sure that's already made illegal by the fact of returning a value instead of a reference. But others seem to disagree about this, so I may need to do some more research. :)

Quote:
Original post by Gage64
I'm not sure I agree.

In general, you mark a parameter as const when you don't want it to be changed inside a function. Now, it's true that if the parameter was passed by value, changing it would not affect the original variable, but if the function should not change the parameter, it's still a logical error. Marking the parameter as const allows the compiler to catch these errors.


This is a more reasonable objection, but I'm not convinced that it would catch very much. For that matter, the decision that a passed-by-value parameter shouldn't be changed strikes me as kind of arbitrary - if it doesn't matter for correctness (and since we're making a copy, how can it?), it's just tying the implementor's hands.

Share this post


Link to post
Share on other sites
visitor    643
Quote:

I'm pretty sure that's already made illegal by the fact of returning a value instead of a reference. But others seem to disagree about this, so I may need to do some more research. :)


It appears that the rules are different for built-in types and user-defined types:


class A
{};

A foo() { return A(); }

int bar() { return 1; }

int main()
{
foo() = A();
bar() = 0;
}



"ComeauTest.c", line 11: error: expression must be a modifiable lvalue
bar() = 0;
^

1 error detected in the compilation of "ComeauTest.c".

Not a word about foo() = A();

Share this post


Link to post
Share on other sites
SiCrane    11839
Quote:
Original post by Zahlman
I'm pretty sure that's already made illegal by the fact of returning a value instead of a reference. But others seem to disagree about this, so I may need to do some more research. :)

The standardese for it is a little complicated. The return value of a function, whether it returns a primitive or a class type is an rvalue. However, if it is a non-const rvalue, you can call non-const member functions on it; this includes overloaded operators, since they are just syntactic sugar for the function call. All class types have automagically generated member functions if they aren't created by the user: operator= is one of them. Therefore, when you have:

A foo();
foo() = A();

The compiler transforms the assignment to the member function call:

foo().operator=(A());

If foo() returned a primitive, foo() = something would fail to compile since operator= for a primitive type is not a function call, so the left hand side of the assignment needs to be an lvalue.

Share this post


Link to post
Share on other sites
zyrolasting    280
Thanks for the first few replies guys, they were helpful. I kind of zoned out when you went to your own separate debate, but I think I got the jist of it.

I am still curious about one more use of const. I came across a function that had const after the function name and return type, but before the parameter list.

float foo const ();

I thought this was especially strange, (and even a syntax error), but it ran.
What can this positioning of the keyword accomplish?

Share this post


Link to post
Share on other sites
JimmyDeemo    156
Hmm that does look strange, if the const was on the other side then it would be a const function, or in other words a function that can be run on a const object. You make want to check your compiler because i'm not sure thats right, can someone else confirm? Anyway below is something about const functions in case thats what you meant. Edit: It doesn't compile in visual studio.

Again is about making sure clients use your types properly. You may realise that for built in types passing by reference to const is often more efficient than pass by value. This is to avoid the construction because of the object using in the function. Note that it needs to be const so you are sure that you object won't be modified.

class CMyClass
{
//...
void doSomething();
void doSomethingConst() const ;
}

void SomeFunction( const MyClass &obj )
{
obj.doSomething(); //This won't compile, see below.
obj.doSomethingConst();
}



Notice that the call to doSomething won't compile. That’s because its not been declared const. The compiler can't be sure that you are invoking a function call that will not modify your object. doSomethingConst is fine, as you have declared it a const function. In other words you are telling the compiler that this function will not modify anything in the object (i.e. member variables ).

In general you should use const quite a lot. When you make new classes you are actually making new types. This means you need to make sure that people use your types properly, or even that you use them properly yourself. If a member
function does not modify any par of the object then it should be declared const, so it can be used by const objects of your type.

Share this post


Link to post
Share on other sites
DevFred    840
Quote:
Original post by zyrolasting
I came across a function that had const after the function name and return type, but before the parameter list.

float foo const ();

Does not compile with g++, maybe you meant float const foo ();?

Share this post


Link to post
Share on other sites
Gage64    1235
Quote:
Original post by Zahlman
Quote:
Original post by Gage64
I'm not sure I agree.

In general, you mark a parameter as const when you don't want it to be changed inside a function. Now, it's true that if the parameter was passed by value, changing it would not affect the original variable, but if the function should not change the parameter, it's still a logical error. Marking the parameter as const allows the compiler to catch these errors.


This is a more reasonable objection, but I'm not convinced that it would catch very much. For that matter, the decision that a passed-by-value parameter shouldn't be changed strikes me as kind of arbitrary - if it doesn't matter for correctness (and since we're making a copy, how can it?), it's just tying the implementor's hands.


I think it can matter for correctness, but I can't think of a good example so here's a bad one:


void print(int arr[], int size) {
size = 13; // Error
for (int i = 0; i < size; ++i)
cout << arr[i] << endl;
}


This function should only print the array so it should not touch the size parameter. If it was marked with const the compiler would have caught this.

Share this post


Link to post
Share on other sites
swiftcoder    18437
Quote:
Original post by Gage64
I think it can matter for correctness, but I can't think of a good example so here's a bad one:


void print(int arr[], int size) {
size = 13; // Error
for (int i = 0; i < size; ++i)
cout << arr[i] << endl;
}


This function should only print the array so it should not touch the size parameter. If it was marked with const the compiler would have caught this.

On the other hand, this is a perfectly legitimate method of reversing the same operation:
void print_reverse(int arr[], int size) {
for (--size; size >= 0; --size)
cout << arr[size] << endl;
}

Share this post


Link to post
Share on other sites
Gage64    1235
Quote:
Original post by swiftcoder
Quote:
Original post by Gage64
I think it can matter for correctness, but I can't think of a good example so here's a bad one:

...

This function should only print the array so it should not touch the size parameter. If it was marked with const the compiler would have caught this.

On the other hand, this is a perfectly legitimate method of reversing the same operation:

...


Well yeah, but the point was that the function I wrote shouldn't touch size and so it should be const. Your function does change size, so obviously it shouldn't be const.

Again, I know it was a bad example. I just think that if you have a parameter that shouldn't change inside the function, making it const can prevent certain logical errors. If later you decide that you do want to change the parameter, you can remove the const modifier.

Share this post


Link to post
Share on other sites
swiftcoder    18437
Quote:
Original post by Gage64
Again, I know it was a bad example. I just think that if you have a parameter that shouldn't change inside the function, making it const can prevent certain logical errors. If later you decide that you do want to change the parameter, you can remove the const modifier.
Forcing a recompile of client code - I don't think an implementation detail like this should be exposed as part of the function's public interface.

This might be a candidate for a pragma (similar to #pragma unused), or just assign the parameter to a const local variable (which will be optimised away), and use that variable instead.

Edit: we seem to have strayed way off topic for the 'for beginners' forum [smile]

Share this post


Link to post
Share on other sites
zyrolasting    280
Thanks guys, I think I get it. I knew what const meant but I was just hazy about any context change when const is put in a less obvious location. I think I'll be good with this now. (Thanks for the link, davi!)

I have a new question in a similar area. I made a static class member. (I understand this is in class scope, not object.) Even so, when I try to compile any build with a static member, I get an unresolved external error. Why is that? I made sure I had a constructor initialize it, and I keep a practice of never altering the value through an object instance.

Share this post


Link to post
Share on other sites
Gage64    1235
Quote:
Original post by zyrolasting
I made a static class member. (I understand this is in class scope, not object.) Even so, when I try to compile any build with a static member, I get an unresolved external error. Why is that?


Clicky.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by SiCrane
If foo() returned a primitive, foo() = something would fail to compile since operator= for a primitive type is not a function call, so the left hand side of the assignment needs to be an lvalue.


Curses, foiled again! ;)

It seems to me like there is usually great pain taken to make operations on objects and on primitives behave the same (e.g. placement-new and manual destructor calls on primitives work fine; constructor-like syntax for primitive initialization), except where logically impossible (member access for example). So this result feels kind of odd. :/

Share this post


Link to post
Share on other sites
rip-off    10979
I share your surprise Zahlman. Yet again I learn something new about C++. I doubt I will ever go a month on this forum without doing so.

While not intuitive, it is obvious when put in terms of function calls.

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