views:

143

answers:

3

So, it's been 5 or 6 years since I've used C++ for a large project, and about half a year since I last had to deal with small/trivial C++ programs and the C++ runtime in general. I've decided I want to re-learn the language, primarily because it might prove very relevant for an upcoming project at work.

I've been working mainly with C and Python, and I'm currently at a point where I'm not even at ease with the for loop syntax below:

for( int i(0); i != n; ++i) {}

although I admit it's not that hard to decipher.

Since I understand there's been a lot of additions to the language as well as libraries and of course idioms, patterns and styles, I'd like to ask for your opinions on good resources that are up to date. I'd like to avoid the tutorials that take the approach "This is C with a lot of extras". I still have my obligatory copy of "The C++ Programming Language" which I'm studying but I honestly don't know exactly where to focus next. Design patterns? Templates and STL/Boost? Something else?

I'm open to all suggestions!

Also, a more specific question regarding typedefs. Is the following:

typedef Type& TypeRef;

generally considered good practice when providing opaque types as part of an API? With a meaningful name, that is. Is it at all similar to the approach adopted by libraries like pthreads or libpcap, and if it is, is it preferable to using a pointer for the same job?

Thanks in advance.

+2  A: 

I never like typedefing away reference or pointer types. It's not possible to effectively hide the fact that a type is a pointer vs. a reference since they have different calling semantics for clients, so this just leads to confusion in my experience.

bshields
+4  A: 

To answer your specific question, typedefs that hide the fact that something is a pointer or a reference are always a bad idea - the same is true in C. Consider for example the opaque type FILE - one still has to explicitly create FILE pointers in order to use it.

As for books, see http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list.

anon
I just found a copy of Meyer's *Effective C++* at work, and since it's suggested, I'll start there. Thanks!
Michael Foukarakis
A: 

The typedef policy taken by the Linux kernel for C is the best. Essentially the policy is to not use typedefs unless you are creating a new type abstraction. This is useful in cases where low-level types different among architectures, but kernel users want a common type. For example u64 is given a specific type, but the underlying type might change between builds or architectures.

typedef u64 unsigned long long;

However, it is highly likely that in C++ there are different idioms using typedefs that are perfectly acceptable, however, I would get comfortable with C before C++.

Perhaps the best way to get re-oriented with C++ is to write may one-off programs that exercise a specific feature. For example, write a template, use a library in Boost, create some threads, allocate some memory. The point isn't to learn all of this stuff, the point is to see and it so you aren't gasping for air later on when it's showtime.

Here is the Linux kernel typedef standard, taken from http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.33.y.git;a=blob_plain;f=Documentation/CodingStyle;hb=HEAD

  Chapter 5: Typedefs

Please don't use things like "vps_t".

It's a mistake to use typedef for structures and pointers. When you see a

vps_t a;

in the source, what does it mean?

In contrast, if it says

struct virtual_container *a;

you can actually tell what "a" is.

Lots of people think that typedefs "help readability". Not so. They are useful only for:

(a) totally opaque objects (where the typedef is actively used to hide what the object is).

 Example: "pte_t" etc. opaque objects that you can only access using
 the proper accessor functions.

 NOTE! Opaqueness and "accessor functions" are not good in themselves.
 The reason we have them for things like pte_t etc. is that there
 really is absolutely _zero_ portably accessible information there.

(b) Clear integer types, where the abstraction helps avoid confusion whether it is "int" or "long".

 u8/u16/u32 are perfectly fine typedefs, although they fit into
 category (d) better than here.

 NOTE! Again - there needs to be a _reason_ for this. If something is
 "unsigned long", then there's no reason to do

typedef unsigned long myflags_t;

 but if there is a clear reason for why it under certain circumstances
 might be an "unsigned int" and under other configurations might be
 "unsigned long", then by all means go ahead and use a typedef.

(c) when you use sparse to literally create a new type for type-checking.

(d) New types which are identical to standard C99 types, in certain exceptional circumstances.

 Although it would only take a short amount of time for the eyes and
 brain to become accustomed to the standard types like 'uint32_t',
 some people object to their use anyway.

 Therefore, the Linux-specific 'u8/u16/u32/u64' types and their
 signed equivalents which are identical to standard types are
 permitted -- although they are not mandatory in new code of your
 own.

 When editing existing code which already uses one or the other set
 of types, you should conform to the existing choices in that code.

(e) Types safe for use in userspace.

 In certain structures which are visible to userspace, we cannot
 require C99 types and cannot use the 'u32' form above. Thus, we
 use __u32 and similar types in all structures which are shared
 with userspace.

Maybe there are other cases too, but the rule should basically be to NEVER EVER use a typedef unless you can clearly match one of those rules.

In general, a pointer, or a struct that has elements that can reasonably be directly accessed should never be a typedef.

Noah Watkins
"I would get comfortable with C before C++" - most people would disagree with you.
anon
Why do you say that? Perhaps it is a matter of perspective. I credit learning C prior to C++ with both a deeper understanding of C++, as well as my deep hatred for C++ ;) I think if time is in your interested, then yeh, C++ first is fine, it isn't that difficult in comparison to C.
Noah Watkins
@Noah I say it because most people would disagree with you - this question has been asked a lot. Certainly, Dr. Stroustrup does. I learned C before C++ myself, but I wouldn't give that any credit for any deep understanding I might have - that would be due to learning assembler before C :-)
anon
@Noah: I am aware of the Linux kernel coding style in general, and while I'm comfortable with C, I wouldn't want to extrapolate C++ idioms from C, without some input from more experienced C++ developers.
Michael Foukarakis
the value of typedefs I think are easier to appreciate in C++ because having several functions that take `std::vector<std::tr1::shared_ptr<MyType>>>` becomes rapidly unreadable.
the_mandrill
@the_mandrill ahh, good example of typedef goodness in C++
Noah Watkins
Not to mention that before C++0x becomes mainstream, you also have to remember to insert the extra spaces between the '`>`' characters...
the_mandrill