C++ is an expert language

Update: I should point out at the beginning that I love C++. Anything below which sounds bitter or critical is borne of a deep and growing love. C++ is a journey into worlds of beauty and strength.

I assert that C++ is an expert language. What do I mean?

You shouldn’t be allowed to use C++ in anger unless you’ve used it for 2 years in anger.

Aside: what should we do about this?

In practice this means that no-one should recruit newbie C++ developers.

The only alternative is to have some kind of apprenticeship system, where all the code written by a newbie is re-written by their mentor for about 2 years. This is a great learning experience, and could weed out people with insufficient capacity for humility to be a C++ programmer. (Note I say capacity for humility, because the actual humility will be provided by the constant crushing of your spirit provided by someone tearing your code apart every day.)

In Java, to create an “array”, and add an object to it, you do this:

MyObj obj = new MyObj();
ArrayList<MyObj> arr = new ArrayList<MyObj>();
arr.add( obj );

In Python, you do this:

obj = MyObj()
arr = []
arr.append( obj )

In C, you do this:

MyStruct obj;
MyStruct arr[50] = { obj };

In Perl, you do this:

my $obj = MyObj->new();
my @arr;
push(@arr,$obj); 

In Pascal, you do this:

var
    arr : ARRAY [1..50] of int;
begin
    arr[1] := 7;
end

In Haskell, you might do something like this (thanks to Neil Mitchell):

[myObj]

Don’t get het up about the fact that these examples do different things: my point is, they are reasonable ways of performing the task (add something to an array) in the languages chosen. (Please do send in corrections, though – none of these were checked and they are probably wrong.)

Note that the C example hides a little more complexity because you need to make sure you tidy up your memory afterwards.

Now, what do you do in C++? It’s just as easy, right?

MyObj obj;
std::vector<MyObj> arr;
arr.push_back( obj );

WRONG!

In the examples above, you don’t need to know what is going on under the covers.

In fact, in general I suggest there are broadly two types of programming language around at the moment: those where you have to know how things work, but where how things work is quite simple (e.g. C, assembly languages, maybe FORTRAN and COBOL) and those which isolate you from how things work (all the rest?).

Where does C++ fit in to this scheme? It is in the unique position of being a language which has incredibly complex things going on under the covers, and you have to know about it!

What do I mean by saying you have to know what’s going on under the covers?

Let’s look at our example again, and ask this question: what types of object can you put in the array? In the other programming languages above, you can essentially put any “normal” objects (where normal is different for each example) into the array.

In C++, here are some of the rules you need to understand about objects you can put into std::vector. You should understand these before you try using std::vector. If you can’t understand them, you should think hard until you do.

Default constructor

If you want to give the size of the vector when you create it (or resize it later), your object must have a default constructor [Stroustrup §16.3.4].

(Note: if you don’t define any other constructors, the compiler will automatically define a default constructor for you (which may or may not do what you want). If you do, the default constructor is the one that can be called without any arguments [Stroustrup §10.4.2].

Example:

$ cat default_constructor_required.cpp
#include <vector>

class MyObject
{
public:
        MyObject( int num )
        {
        }
};

int main( int argc, const char* argv[] )
{
        std::vector<MyObject> arr( 5 );
}

$ g++ default_constructor_required.cpp
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_vector.h:
In constructor ‘std::vector<_Tp, _Alloc>::vector(size_t) [with
_Tp = MyObject, _Alloc = std::allocator<MyObject>]’:
default_constructor_required.cpp:12:   instantiated from here
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_vector.h:219:
error: no matching function for call to ‘MyObject::MyObject()’
default_constructor_required.cpp:5: note: candidates are: MyObject::MyObject(int)
default_constructor_required.cpp:4: note:                 MyObject::MyObject(const MyObject&)

Nice error message, eh?

(Note: if your array contains a built-in type (e.g. int) it will be initialised to 0 in its default constructor [Stroustrup §4.9.5].

If you don’t want to give the size of the vector when you create it (not recommended), then you don’t need a default constructor in your object [Stroustrup §16.3.4].

Copy constructor

Your object must also have a copy constructor. Example:

$ cat copy_constructor_required.cpp
#include <vector>

class MyObject
{
public:
        MyObject()
        {
        }
private:
        MyObject( const MyObject& );
};

int main( int argc, const char* argv[] )
{
        std::vector<MyObject> arr( 5 );
}

$ g++ copy_constructor_required.cpp
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_vector.h: In
constructor ‘std::vector<_Tp, _Alloc>::vector(size_t) [with _Tp = MyObject,
_Alloc = std::allocator<MyObject>]’:
copy_constructor_required.cpp:15:   instantiated from here
copy_constructor_required.cpp:10: error: ‘MyObject::MyObject(const MyObject&)’ is private
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_vector.h:219:
error: within this context
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_construct.h:
In function ‘void std::_Construct(_T1*, const _T2&) [with _T1 = MyObject, _T2 = MyObject]’:
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_uninitialized.h:194:
   instantiated from ‘void std::__uninitialized_fill_n_aux(_ForwardIterator, _Size,
 const _Tp&, __false_type) [with _ForwardIterator = MyObject*, _Size = unsigned int, _Tp = MyObject]’
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_uninitialized.h:218:
   instantiated from ‘void std::uninitialized_fill_n(_ForwardIterator, _Size,
 const _Tp&) [with _ForwardIterator = MyObject*, _Size = unsigned int, _Tp = MyObject]’
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_uninitialized.h:310:
   instantiated from ‘void std::__uninitialized_fill_n_a(_ForwardIterator, _Size,
 const _Tp&, std::allocator<_Tp2>) [with _ForwardIterator = MyObject*, _Size
 = unsigned int, _Tp = MyObject, _Tp2 = MyObject]’
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_vector.h:219:
   instantiated from ‘std::vector<_Tp, _Alloc>::vector(size_t) [with _Tp =
 MyObject, _Alloc = std::allocator<MyObject>]’
copy_constructor_required.cpp:15:   instantiated from here
copy_constructor_required.cpp:10: error: ‘MyObject::MyObject(const
 MyObject&)’ is private
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_construct.h:81:
 error: within this context

(Aside: this program is 181 bytes, and the error message is 1950 bytes.)

Assignment operator

You also need operator=. Example:

$ cat assignment_operator_required.cpp
#include <vector>

class MyObject
{
private:
        MyObject& operator=( const MyObject& );
};

int main( int argc, const char* argv[] )
{
        MyObject obj;
        std::vector<MyObject> arr;
        arr.push_back( obj );
}

$ g++ assignment_operator_required.cpp
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/vector.tcc:
In member function ‘void std::vector<_Tp,
_Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename _Alloc::pointer,
std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = MyObject, _Alloc =
std::allocator<MyObject>]’:
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_vector.h:610:
instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with
_Tp = MyObject, _Alloc = std::allocator<MyObject>]’
assignment_operator_required.cpp:13: instantiated from here
assignment_operator_required.cpp:6: error: ‘MyObject&
MyObject::operator=(const MyObject&)’ is private
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/vector.tcc:260:
error: within this context
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_algobase.h:
In static member function ‘static _BI2 std::__copy_backward<_BoolType,
std::random_access_iterator_tag>::copy_b(_BI1, _BI1, _BI2) [with _BI1 =
MyObject*, _BI2 = MyObject*, bool _BoolType = false]’:
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_algobase.h:443:
instantiated from ‘_BI2 std::__copy_backward_aux(_BI1, _BI1, _BI2) [with _BI1
= MyObject*, _BI2 = MyObject*]’
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_algobase.h:482:
instantiated from ‘static _BI2 std::__copy_backward_normal<true,
true>::copy_b_n(_BI1, _BI1, _BI2) [with _BI1 =
__gnu_cxx::__normal_iterator<MyObject*, std::vector<MyObject,
std::allocator<MyObject> > >, _BI2 = __gnu_cxx::__normal_iterator<MyObject*,
std::vector<MyObject, std::allocator<MyObject> > >]’
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_algobase.h:517:
instantiated from ‘_BI2 std::copy_backward(_BI1, _BI1, _BI2) [with _BI1 =
__gnu_cxx::__normal_iterator<MyObject*, std::vector<MyObject,
std::allocator<MyObject> > >, _BI2 = __gnu_cxx::__normal_iterator<MyObject*,
std::vector<MyObject, std::allocator<MyObject> > >]’
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/vector.tcc:257:
instantiated from ‘void std::vector<_Tp,
_Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename _Alloc::pointer,
std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = MyObject, _Alloc =
std::allocator<MyObject>]’
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_vector.h:610:
instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with
_Tp = MyObject, _Alloc = std::allocator<MyObject>]’
assignment_operator_required.cpp:13: instantiated from here
assignment_operator_required.cpp:6: error: ‘MyObject&
MyObject::operator=(const MyObject&)’ is private
/usr/lib/gcc/i486-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/stl_algobase.h:412:
error: within this context

(Aside: program is 202 bytes, error is 2837 bytes.)

Excuses

Don’t give me that “the compiler will provide them for you” excuse. What the compiler provides is often wrong, unless you’ve been careful to ensure you don’t own any members by holding pointers to them: i.e. if you’ve fully understood the problem I am setting out and avoided the pitfalls.

Conclusion

I assert that C++ is an expert language. Quite apart from the fact that the method names on STL objects use archane phrases like “push_back” rather than “add”, and the error messages you get from popular compilers are huge and almost incomprehensible, my main point is that you have to understand the basics of how the standard library is implemented, before you can use it. This is expert behaviour.

I have illustrated this point by showing what you need to know to use the standard resizeable array type in C++. You need to know a lot.

More on whether the fact that C++ is an expert language is a bad thing, later.

Update: simplified the C example thanks to Edmund’s suggestion.

Update 2: corrected the Java example thanks to Anon’s comment.

Update 3: corrected the Haskell example thanks to Neil Mitchell’s comment.

44 thoughts on “C++ is an expert language”

  1. Your Haskell and Python examples are whack. Those are the only two I checked, but you should probably be more careful if you’re going to make a point about language inexperience =-)

    > obj = MyObj()
    > arr = []
    > arr.append( obj )

    No one would do this. This style is too much like Java =-P A real Pythonist would do it simply like this, unless they needed the handle to obj.

    arr = [MyObj()]

    The Haskell code is more less good.
    > [ get_my_obj :: MyObj ]
    In what you have, you annotate the type of get_my_obj inside a list. There are many subtle errors here. First, annotations in Haskell are almost always omitted except for top-level functions. The type checker can infer it all. Next, it’s very awkward to put the annotation INSIDE the list (though, it is totally legal). If the type checker did indeed require get_my_obj to be annotated, it would almost always be written as:

    [get_my_obj] :: [MyObj]

    Showing that the list, as a whole, is a list containing MyObj objects. Lastly, and this one is the biggest issue, get_my_obj is named as if it were a factory for a MyObj object. But things are weird in Haskell, and get_my_obj is a *constant*. That is, it doesn’t create a new object every time this line gets run. It returns the same one every time. What you want to do is probably: 1) apply some arguments to it; 2) use a constructor and apply arguments to that, not a function; or 3) use a monad for a side-effectful object creation.

    1)
    [sin 1.0]

    2)
    [Person “Haskell” “Curry”]

    3)
    do {
    input

  2. However, using C++ has the huge advantages that make it all worth it:

    [ ] easier to manage
    [ ] performs faster
    [ ] faster to code in
    [ ] easier to debug
    [ ] better object oriented logic
    [x] has been around for a long time
    [x] shouldn’t be used by anyone who hasn’t been coding in it for two years

    That sounds sarcastic but “has been around for a long time” is damning — it curses us with all that legacy code.

    The frustrating aspect of C++’s “expert”-ness is that it’s a volume of details, not concepts that are required to be a competent C++ coder. Internalizing “push_back” is not going to contribute to any lifelong coding skill, that’s for sure.

  3. But one problem is that, with languages like Ruby and Python becoming more popular, and C still being the oldschool powerhorse – why is the complexity inside C++ needed?

    I mean newbies produce more errors everywhere, and in C++ you shoot at your foot and the whole neighbor village is gone. But why use C++ when one has C available and can combine it with i.e. Ruby anyway?

    To me it seems that the language is just too complex, because if you continually surprise humans, than who is at fault – the language, or the human?

  4. perl could be simplifies to
    push @arr, MyObj->new();

    The temproary variable isn’t required. Python quite likely would support similar shortening

  5. I personally like to believe your point that you have to understand how things work under the hood of a language should be applied to any language. Basic logical computer science concepts like arrays and stack and so forth are arguably universal in the world of computer programming, the language of choice does not change it.

    I have been coding Java for almost 8 years now, and yes I admit due to its high level nature I am still learning a thing or two now and then. The difference is that I fully understand these experts “concepts”, and fully confident I can implement it in almost any language of my choice since the computational logic does not change (barring language implementation differences, but not even that should be an issue).

    I agree with you main point of C++ being a expert language, but I believe an expert should necessarily be distinguished by his/hers language of choice.

  6. I personally like your point, but the idea that you have to understand how things work under the hood of a language should be applied to any language. Basic logical computer science concepts like arrays and stacks and so forth are arguably universal in the world of computer programming, the language of choice does not change it.

    I have been coding Java for almost 8 years now, and yes I admit due to its high level nature I am still learning a thing or two about JVM inner workings now and then. The difference is that I fully understand these experts “concepts”, and fully confident I can implement it in almost any language of my choice since the computational logic does not change (barring language implementation differences, but not even that should be an issue).

    I agree with you main point of C++ being a expert language, but I believe an expert should necessarily be distinguished by his/hers language of choice.

  7. I think you are right. I worked hard at becoming a good C++ programmer, and it wasn’t until I had a fairly deep understanding of the language, compiler, and runtime libs that it all started making any sense.

    2 years is probably a little long, but 6 months of fairly intense work with the help of someone who already Knows The Way would be a reasonable minimum.

    Personally, now that I’ve actually been working with Python, I can’t ever see myself choosing C++ for new work. Python with C modules for the compute-intensive stuff is WAY more attractive for anything I can see myself doing.

    I suspect that there are cases where C++ really makes sense. Anybody out there have any good examples? And I’m not talking about cases where the reason for C++ is the existence of a huge body of legacy code that can’t be changed…..

  8. You don’t have to know how the STL is implemented, because the requirements on the type traits of vector elements are specified in the standard. It would be ridiculous to require you to know how the STL is implemented, because there are many implementations; their focal point, however, is the standard.

  9. if people are not going to hire newbs, how are they going to become !newbs ? (i leave to you what the negation of newb is :) )

    as a side comment, i know at least one guy that knew more c++ that some “experienced” c++ developers…

    everyone was a newb once, right??

  10. Like the C example, the PErl can be simplified from this:

    my $obj = MyObj->new();
    my @arr;
    push(@arr,$obj);

    To this:

    my $obj = MyObj->new();
    my @arr = ( $obj );

    Or even (if you are careful):

    my @arr = ( MyObj->new() );

  11. Your example cites only references to the Standard Template Library, which is not an integral part of the C++ language itself. I would agree that the STL is overly complex and does not work in what would seem to be a logical manner, but I don’t know that I would go so far as to claim that “C++ is an expert language.”

  12. “I have illustrated this point by showing what you need to know to use the standard resizeable array type in C++. You need to know a lot.”

    The three things you note about C++ are about the first thing most books mention (along with providing a (possibly virtual) destructor), so I’d venture to guess that most people venturing to use the STL would have that under their belts by then.

  13. To me it sounds more like you are saying C++ is a language for people that have actually used it for longer than a week.

  14. I have to call bollux on this entire post. The truth is, most developers writing C++ code are doing so using MFC, or the Borland equivalent (C++ Builder) – especially in Europe. I’ve worked for 4 different companies (all successful) over the past 10 years. All used C++ as the primary programming language, and all used either MFC or VCL classes as the backbone of all development. None of them used the STL in any way.

    For my very first C++ job I learned the STL, (read the books and so on). But this learning was never used, as the ‘simplicity’ of the other established libraries always won out at the higher, decision making level.

    Yes, it’s true that for certain jobs you’re better off writing your own string list, or whatever – but for most Enterprise software (Read: money making software), this is simply not EVER necessary!

    This post reads as old-school, pretentious, bullcrap! What’s next – every car should have a Porsche engine? Every medical procedure MUST be carried out in the number 1 US hospital? Every wife should appear in Maxim’s top 100 list before the ring is offered, otherwise they’re too ugly and should be dumped at the alter?

    Get a grip! – on reality that is.

  15. I can’t say I agree with this, for one simple reason:

    Every class in C++ must have a default constructor, a copy constructor, and an assignment operator.

    Granted, the compiler will let you CREATE a class without these, but even a C++ newbie, even somebody who’s had a single class in the language, knows that every class in C++ must have a default constructor, a copy constructor, and an assignment operator.

    Once it becomes automatic to create these methods (and they’re usually very simple to create) for every class you write, you don’t really run into these odd problems with the STL.

  16. Apologies for the delay approving all your posts. I have been drowning under a torrent of spam for the last couple of weeks. I will reply to each comment personally this evening or tomorrow.

  17. Yeah .. You need to know what you’re doing, which is completely unlike every other language on the planet. Or, perhaps, you can just use the C example in the same old way and move on with your life.

    I agree with B.G. – get a grip.

  18. There are two senses of the phrase “how it works.” One is how it works on the inside — in software terms, how it is implemented. The other is how it works from the perspective of someone using it — in software terms, the interface.

    In all of the languages that you cited, the array feature has an interface with which the programmer must operate. The interface to the C++ std::vector is certainly complicated, and you could argue that it is overcomplicated, but the details you cited as things you have to know about how it works have nothing to do with the implementation of std::vector, they are only parts of the complicated interface of std::vector.

    So, while you can argue that C++ is complicated, your example only shows that C++ is quantitatively more complicated. If you want to argue that C++ occupies an entirely separate “complication class,” you will need a different argument. Such an argument is probably possible.

  19. I agree that newbee c++ coders can be detrimental in the core of a complex project. Bad programmers are detrimental, regardless of the language.

    The issue raised in this article is less about cpp and more about garbage collection/reference counting.

    Of the ‘simple’ examples given, most of them use reference types and garbage collection/reference counting.

    Pascal used array of int, nothing complex there in cpp either

    C example uses value type copied by value. Ownership of members is ‘undefined’, a crash waiting to happen.

    Most of the CPP errors result from passing the object by value. The compiler is warning you that it can’t do it correctly without being told how. Change to something like this for semantics comparable to the other examples.

    typedef smart_ptr myobj_ptr
    std::vector arr;
    arr.push_back( new MyObj );

  20. To C++’s defence here: the program you have written here is semantically very different from the other languages. In C++ you have a vector of MyObject, in all other languages (besides C) you have an array of pointers to objects. The pointer variant in C++ would be:

    MyObj obj;
    std::vector arr;
    arr.push_back( &obj );

    No default constructors, copy constructors or assignment operators needed. Actually, I don’t know of any other language than C/C++ where you can have arrays with your own objects as value types.

    However, I wouldn’t argue that you’re wrong. C++ is an arcane and complex language. You can gain a little efficiency and direct control of the computer hardware, but it is rarely worth all the problems.

  21. The non-C++ examples are a perfect illustration why there shouldn’t be a C++ newbie anymore on this planet.
    Like, if you know everything about the inner workings of a combustion engine would that make you a better driver?
    In my 20 years as a C programmer I’ve seen worse C++ programmers (and they weren’t newbies) than C ones.

  22. ArrayList arr = Arrays.asList(new MyObj());

    And still… strongly typed, compiler checked…

  23. Wooops… to fast with the copy’n’paste. Should be:

    List arr = Arrays.asList(new MyObj());

  24. Tac-Tics:

    arr = [MyObj()]

    I was expecting to use the MyObj later, and/or do some more stuff to it before I added it to the array. I write quite a lot of Python, so obviously at least one people does use this kind of style. I admit it is probably quite Java-y.

    The Haskell code is more less good.

    :) The Haskell example was added for fun and is my first ever line of Haskell. Sounds like I made quite a few mistakes. I have corrected it based on another comment. Please let me know if the corrected version is wrong in any way.

    you should probably be more careful if you’re going to make a point about language inexperience

    Point taken :).

    T4C:

    it’s a volume of details, not concepts that are required

    I think there is a large number of very complex concepts too – more than most languages.

    markus:

    But one problem is that, with languages like Ruby and Python becoming more popular, and C still being the oldschool powerhorse – why is the complexity inside C++ needed?

    Ruby or Python with C for the fast parts is a compelling alternative in some situations, but C++ can really express some things you can’t do in other languages… and isn’t it just more exciting to code in?

    noah:

    Thanks, yes, I was assuming I’d be doing something to the MyObj before putting it into the array. I don’t know why I was assuming that…

    kL:

    array ~= obj;

    Wow, cool operator!

    Riaan Minne:

    the idea that you have to understand how things work under the hood of a language should be applied to any language

    My argument is that in C++ it is necessary to know how things work before you even start. Of course, one can become an expert in any programming language, and yes, many of the concepts you acquire are transferrable. By no means all, though.

    rrwood:

    I suspect that there are cases where C++ really makes sense

    Yes, and I’m not at all saying you shouldn’t use it – I’m mainly saying you should make sure you hire gurus, I think. Actually, I’m not completely sure what I am saying you should do – I’m basically just saying that C++ is for experts.

    Incidentally, one compelling area for using C++ is embedded. But I think it can be great for anything.

    Err:

    You don’t have to know how the STL is implemented, because the requirements on the type traits of vector elements are specified in the standard.

    That is technically true. However, the only way I can think of to remember those otherwise arbitrary restrictions is to have some kind of mental model of what is going on underneath. That’s certainly how I remember them (when I do). If you prefer to remember them by memorising the standard, then my argument is simply that there is a large amount of arbitrary information which needs to be learnt before you use STL containers.

    Anon:

    do you mean ArrayList

    Thank you, yes, I am an idiot. Example corrected.

    erm….:

    if people are not going to hire newbs, how are they going to become !newbs ?

    Yes, that is a major problem. I started learning C++ during my PhD, which helped because I had no employer as such, but I have become a lot better (certainly not expert…) since I started using it for my job. I am very grateful to my employer for taking me on, but very regretful about a lot of the code I wrote in the past – I wish I had been mentored much more.

    Ric

    Like the C example, the PErl can be simplified from this:
    …snip…
    To this:

    my $obj = MyObj->new();
    my @arr = ( $obj );

    Simplified or shortened? I prefer the longer version to clarify what each step does (especially in an example…).

    fname lname:

    DIM a$
    INPUT “Enter your name”, a$
    PRINT “Hello, “, a$

    Mike:

    Your example cites only references to the Standard Template Library, which is not an integral part of the C++ language itself.

    Since it’s part of the standard, I would argue that it is.

    I would agree that the STL is overly complex

    It remains an open question as to whether it is possible to implement a powerful library in C++ that does not require you to have a good feel for how it works under the covers before you use it. Maybe someone can suggest an example of such a library.

    Perhaps the compromise would be in terms of performance, which would take away a lot of people’s reasons for using C++ in the first place.

    BTW, I never said that STL is overly complex, only that it is complex.

    Edgardo Portal

    The three things you note about C++ are about the first thing most books mention (along with providing a (possibly virtual) destructor), so I’d venture to guess that most people venturing to use the STL would have that under their belts by then.

    I certainly didn’t have this under my belt when I first used STL containers – I just got scared and put pointers into STL containers and had to manage the memory myself. Understanding by-value semantics came later for me. Perhaps it was because I didn’t really read books. (I’m trying to correct that now.)

    Sgt. Pepper:

    Another stupid and pointless C++ flame…

    It’s not a flame – I love C++!

    I hope it’s not pointless – maybe it will help us think about things like:

    – How to teach C++? (e.g. Charles Bailey and I had an interesting chat today about whether you can teach C++ by starting with by-value semantics and only covering pointers later. Hopefully he’ll blog about that, along with the myriad ways he disagrees with me :)

    – How to write libraries?

    – The need for mentoring of new developers?

    Max:

    To me it sounds more like you are saying C++ is a language for people that have actually used it for longer than a week.

    I have used it for several years and have loads left to learn. I also know people who are way, way stronger than me and they say they have a lot left to learn as well. You could be an incredibly fast learner.

    B.G.:

    The truth is, most developers writing C++ code are doing so using MFC, or the Borland equivalent (C++ Builder) – especially in Europe.

    I work as a programmer in Europe and I use STL whenever I can, which is a lot. All the underlying classes we use company-wide are based on STL templates and algorithms, where they are appropriate.

    STL is excellent! I’ve heard that MFC is horrible, but I’ve never used it.

    One reason to use the standard facilities is portability. Surely for “Enterprise” software this is important? Our product runs on 4 platforms, only one of which has MFC.

    Lots of people at last week’s ACCU conference were very interested in STL, so some people are definitely using it.

    This post reads as old-school, pretentious, bullcrap! What’s next – every car should have a Porsche engine? Every medical procedure MUST be carried out in the number 1 US hospital? Every wife should appear in Maxim’s top 100 list before the ring is offered, otherwise they’re too ugly and should be dumped at the alter?

    I don’t understand your point. Please could you be more explicit?

  25. Kyle:

    Granted, the compiler will let you CREATE a class without these, but even a C++ newbie, even somebody who’s had a single class in the language, knows that every class in C++ must have a default constructor, a copy constructor, and an assignment operator.

    No, every class with value semantics needs these. John Lakos’ talk “Toward a Common Intuition and Reusable Testing Methodology” at the ACCU conference (which inspired my use of this example here) was very interesting on this topic. I don’t know whether he has put his slides online – they might be interesting, but really you’d need to see the video to get the full force of it!

    Misc:

    Yeah .. You need to know what you’re doing, which is completely unlike every other language on the planet.

    I presume this is meant sarcastically. I think there are degrees of “knowing what you’re doing”, and I think C++ requires a higher degree.

    Karl:

    the details you cited as things you have to know about how it works have nothing to do with the implementation of std::vector, they are only parts of the complicated interface of std::vector.

    Yes, agreed in theory. As I mentioned in another comment, though, in practice, the only way I have found to remember such details is to think (in general terms) about how the artefacts I am using are implemented. Stroustrup encourages this approach, probably partly because it is a book intended to help those who implement the language as well as those who use it.

    If you want to argue that C++ occupies an entirely separate “complication class,” you will need a different argument.

    I agree that it is perfectly possible to remember requirements like these without thinking about the implementation, but I can’t think of an easier way.

    I think I’d be happy to say that C++ is more complex than other languages, rather than belonging to a separate class.

    Frank:

    Bad programmers are detrimental, regardless of the language.

    Agreed. What about inexperienced coders? How damaging are they? How easy is it to spot their errors?

    The issue raised in this article is less about cpp and more about garbage collection/reference counting.

    I’d say it was a more general point than that. In general I have found that people documenting C++ libraries talk about the implementation (in general terms) quite often, whereas I have found that that is much more rare when documenting libraries for other languages. Perhaps it is purely a cultural issue.

    Pascal used array of int, nothing complex there in cpp either

    My point here is that Pascal is simpler. If you want more complex semantics you have to write them yourself.

    C example uses value type copied by value. Ownership of members is ‘undefined’, a crash waiting to happen.

    Yes, if your struct contains pointers.

    Most of the CPP errors result from passing the object by value. The compiler is warning you that it can’t do it correctly without being told how.

    Yes, the existence (and use in STL) of by-value semantics in C++ is an example of one of the ways it is more complex than less flexible languages.

    raincat:

    To C++’s defence here: the program you have written here is semantically very different from the other languages.

    Actually, I don’t know of any other language than C/C++ where you can have arrays with your own objects as value types.

    Yes, that is exactly my point – having these difficult to understand facilities available makes C++ complex.

    However, I wouldn’t argue that you’re wrong. C++ is an arcane and complex language. You can gain a little efficiency and direct control of the computer hardware, but it is rarely worth all the problems.

    I think I really must have put myself across badly if it sounded like I was criticising C++.

    I agree that C++ is complex, and sometimes arcane, but it is also an amazing phenomenon, full of power and beauty, and incredibly useful for almost anything.

  26. Wow. Good info.

    Are there some good books that discuss this type of thing ? I’ve had a couple of C++ classes at college… and you know I’ve never run into that information before.

    Thanks for the heads up….
    Glen

  27. Hi Glen, glad to hear you found it useful. As someone else pointed out, don’t forget about the destructor (although if you don’t have any raw pointer members, the compiler-provided one may well be fine).

    I use Stroustrup, but I’m not convinced it is the best place to start. Whenever anyone asks me about books I usually just say “always choose an O’Reilly”, but in this case I happen to think that Practical C++ Programming is not that good (it’s the book I used to learn, and I didn’t find it inspiring).

    This one looks quite cool: How Not to Program in C++, but I’ve never read it.

    If you want to keep going deeper, I’ve found some really interesting stuff on the Dr Dobb’s Journal web site, and I can recommend ACCU‘s publications Overload and CVu.

    Scott Meyers‘ books “Effective C++” and “More Effective C++” are excellent, but not aimed at beginners. They cover exactly the type of thing I described above in this blog entry.

    Perhaps others have suggestions for good books they used to learn C++?

  28. MFC does suck. And sucks hard (at least back in 2001 when I had to use it).

    As far as understanding the under-workings of the STL, I think, instead, that a basic understanding of how different data structures work and where they are appropriate is sufficient, especially since, as previously pointed out, that the STL is implemented differently all over the place.

    Also, PHP:

    $arr = array( new MyObj() );

    and JavaScript:

    var MyObj = {}, arr = [ MyObj ];

  29. Article- I agree that many details make this complicated, but it’s not *that* fundamentally bad. For most of the other languages, you inevitably have to understand the difference between references and values; Ruby tries to turn everything into a reference, but if you want to be clever and create a list of ten empty strings via [“”] * 10, the fundamental problem comes up again as soon as you try to modify one of them. In Java you also have to understand the (annoying) difference between primitives and objects.
    But once you understand to divide your classes into value types and noncopyable reference types, and use tr1 pointers to handle the reference types, it gets so much easier and the whole design suddenly makes a lot of sense, though technically, even more things are happening under the surface.

    I don’t understand why everything surrounding copying is brought up so often, while I haven’t read much criticism for completely failed concepts such as argument dependent lookup, which is PHP-class bad in that it makes a seemingly harmless feature (calling a function) overly complex. Templates being complex is just something you should expect ;)

    Kyle- Totally disagree. Define copying/assignment at the lowest level, i.e. smart pointers, containers etc., then just do nothing in the upper levels. Things owning an object that can’t be copied have a scoped_ptr member so aren’t copyable (rightly so!), structs that only have some strings and ints can be copied. Problem solved ;)

  30. Hey Andy…

    THanks so much.

    The Scott Meyers’ books are probably what I’m looking for. After taking a few C++ classes at school, I’ve been through several books — and very important information such as the above, aren’t covered in beginning books.

    Most of these beginning books cover syntax, a little OOP theory, a dash of UML 2 and after 800 pages and 15 chapters… congrats! You can put C++ on your resume now!

    So this is very helpful stuff.

    The web of course is an extremely helpful tool — but to answer specific questions without knowing why, it’s great. On example: What’s the fastest way to copy very large amounts of small files. The web has that answer, but usually never “why” the code is that answer. They don’t go into the depth and background you need to know… to get some experience so you can take that knowledge forth and prosper.

    Keep up the great blog.

  31. At college I was taught how to program using C++, but I didn’t really _learn_ C++ till I read C++ Primer (4th ed) by Stan Lippman, cover-to-cover. I think it’s probably the best book for learning the fundamentals and how to use C++ “the right way”. Admittedly, it’s a very long read, but it’s a good place to start if you want to grok C++ instead of just getting by.

    Stoustrup’s book seems more focused on the language itself and less focused on how to use it. But, if you want to know why C++ is the way it is (although probably most people don’t), check out his other book The Design and Evolution of C++.

    Nowadays, I have to consult the C++ standard itself once in a while (the only way to get a definitive answer on some very specific questions). ANSI sells it for about $30 (which is still highway robbery for a language standard). Don’t be afraid to get yourself a copy and have it as a reference.

    I haven’t read the Scott Meyers books, but they are probably very good, not so much for learning the basics, but for how to solve the kinds of problems that come up a lot when using C++ in the real world. For this type of thing, also check out Herb Sutter’s books and his Guru of the Week articles.

    In any case, you are definitely right, C++ is geared more toward experts. Hopefully C++0x will change that somewhat. However, I’m of the opinion that becoming a C++ expert is worth the effort. (Can you be an expert user of a language without being an expert in the language itself?)

    Warning: Use of RAII may cause your debugging skills to falter, because you won’t need to use the debugger as often.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.