Navigation

What is so hard about C++?

C++ may be quite simple if you just write it in they way you want which probably is a mixture of C and Java style OOP
What is so hard about C++

C++ may be quite simple if you just write it in they way you want which probably is a mixture of C and Java style OOP.
Have in mind though that C++ aims to:
1) Be a system language exposing the underlying hardware architecture.
2) Be a multi-paradigm language with advanced abstraction facilities
3) Maintain backward compatibility with C and its previous versions
In practice you normally use C++ in order to utilise both (1) and (2) known together as Zero Cost Abstractions. A C++ codebase often has as requirements:
R1: Efficient: minimal constant factors, zero-copy( shared memory) etc
R2: Abstracted and maintainable.
R3:  Concurrency
R4: Safe. No segmentation faults, buffer overflows etc
.
People who think that writing C++ is easy either do not operate under so strict requirements ( and they should probably pick another language if they can) OR they wrongly evaluate their success.

Basic Example where R4 fails in a subtle way.
struct A
{
    A(int i) : i(i) {}
    bool isGood() { return i == 100000; }
    int get() { return i;}
private:
    int i;
};
void f()
{
    std::vector<A> v; // Abstraction facilities: automated memory management
    A* last_good = nullptr; // Compatibility with C raw pointers
    for (int i=0; i < 1000000; ++i)
    {
        v.emplace_back( i ); // Zero Cost Abstractions
        if ( v.back().isGood) )
        {
            last_good = &v.back(); // pointer from reference
        }
    }
    if ( last_good)
    {
        std::cout << "last good=" << last_good->get() << std::endl; // SEGFAULT :)
    }
}

Hidden problem : "If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated."  std::vector::emplace_back - cppreference.com


Invisible Problems
The above -very simple and well known- problem illustrates that low-level memory management(pointer), high level abstractions (vector) and zero-cost philosophy ( c++ will not bother to tell you it moved the vector's content) create difficulties that most people don't fully appreciate. 
Problems of category R1 bring even more complex issues such as perfect forwarding, cache locality, atomics vs locks etc. You must understand borth the C++ implementations and the underlying hardware. Example std::string copy under some implementations is not a copy but a copy-on-write. Some other implementations of std::string contain some small buffer and only allocate on heap if you exceed it. The above affects both multithreading and perfect forwarding.
To make things worst trying to solve the above problem problems as a Library developer is the most complex aspect of C++ because you are expected to operate on generic/ templated types. See for instance one header file from the Boost libraries that implements the variant type - a very simple idea by itself: boost/variant/variant.hpp - 1.57.0 Unfortunately techniques used for libraries can affect the call side as well so may need to be at least familiar with them.

Modern C++ Style requires experience
To write code under such requirements there are some very specific patterns that the C++ community has developed over the years. They are some times referred as Modern C++ Style. That style was created after years of experimentation.
In order to write efficient modern C++ you need:
-Some reasonable understanding of the underlying C++ standard which is very complex  AND it's possible implementations.
- Some good grasp of C++  history and literature. You need that in order to know all the common patterns what are their limitations, how they play with each other and the anti-patterns( always looking harmless ) so when you see them in a codebase to correct them or at least defend from them. 
Normally that is achieved only after some years of experience.

Quick Evaluation

1) Read view random questions from C++ FAQ are those issues familiar to you ?
2) Try to read the standard. Some keywords to look for( Two phase lookup, ADL lookup, rvalue references, move semantics)

3) Try to read the implementation of shared_ptr from boost boost/smart_ptr/shared_ptr.hpp - 1.57.0 and compare it to that of your favourite standard library. Pick a well known C++ Library such as Boost, Intel TBB or Facebook Folly. Try to read their implementation for a concurrent queue and compare them. For something easier browse  Microsoft/GSL.

Conclusion
They key point is that in order to evaluate the full complexity of C++ you must look on existing industry practices  and  not your own code. Your code may be both simple and correct but most C++ out there may not.
I think that you are right. Complexity of C++ does not stem from ideas that are hard to grasp conceptually. It stems from having too many simple ideas that are hard to combine with each other in a way that has both efficient and safe implementation. For scientific computing you probably don't need to care about all that complexity though.

>> Also you can read: Is C++ really as hard as people say
مشاركة

أضف تعليق:

0 comments: