Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

"My precious language isn't broken! It's not! Not! Not!" Strostrup writes something like this about once a year. There's some denial there.

The basic problem with C++ is that it's hard to tell if something really bad is happening. Think of C++ from the view of the maintenance programmer assigned to figure out why a C++ program is crashing intermittently. Or worse, the security expert trying to figure out how a system was penetrated. C++ has hiding ("abstraction") without safety. This is a bad combination, one seen in few other major languages.

We make progress in programming partly by having the language eliminate some problem. High-level languages mean you don't have to worry about register allocation, saving and restoring registers, or calling sequence conventions. Assembler programmers have to obsess on those issues. C++ doesn't eliminate any problems from C. It helps with some of them, but not to the point that they're just gone.

The three big questions in C are "How big is it?", "Who owns it?", and "Who locks it?". C++ helps a lot with the first one, even though it doesn't have enough subscript checking to guarantee the absence of buffer overflows.

C++ has struggled with the second one, with three rounds of auto_ptr, unique_ptr, and now reference-counted smart pointers. But because these are an afterthought, implemented using templates, they're neither optimized nor airtight. The mold keeps seeping through the wallpaper, in the form of raw pointers. Rust has a designed-in solution to this problem. (Rust's borrow checker is perhaps where C++ should have gone, but C++ will never get there.)

C++ as a language has no clue about who locks what. The language totally ignores concurrency. That's said to be an operating system problem. This is now a very dated concept.

(As I say occasionally, I really hope the Rust crowd doesn't screw up. They address all three of those big questions in effective ways. But I see too much use of "unsafe" in Rust code, which indicates weaknesses in the language design. The use of Rust's "unsafe" for "performance" is a big problem. From a semantic standpoint, only "Vec" needs "unsafe", because somebody has to convert raw memory to an array of objects. Everything else can be built on top of "Vec". But there is unsafe code for "performance" in hash classes and such.)



How is abstraction unsafe?

Additionally, raw pointers are not dangerous. If you're passing them around as const pointers, the receiver can't do things like deleting them. If you are writing a container class (instead of using one of the existing myriad of containers in the STL) then you can use raw pointers. But typically you would not need to write your own container class; just use one of the STL's and the move semantics. You can then use references everywhere instead. Or const references. Everyone forgets about const correctness in their C++ bashing.

For concurrency, you may wish to see http://en.cppreference.com/w/cpp/thread

There's even mutexes in there.


Creating a dangling const pointer is pretty trivial. Hell, make it a const reference.

    #include <iostream>

    struct Foo {
        const int &dangling;

        Foo(const int &dangling): dangling(dangling) { }
    };

    Foo foo() {
        int dangling = 0;
        Foo foo(dangling);
        return foo;
    }

    int main() {
        std::cout << foo().dangling << std::endl;
        return 0;
    }

Neither g++ nor clang warn on this, either. I am not sure why you think const pointers are safe. They aren't. Flat out.


Well I was assuming for pointers that they'd be initialised to something sensible. That would be a coding standard problem if they're not.

The example you give is also a problem with coding standards, I'd argue. It isn't the languages fault that you're using a reference that's going out of scope - that's just bad coding. (A pointer going out of scope isn't so bad, no?)


How is abstraction (hiding) unsafe?

Objects hide their implementation details. An object is only a valid abstraction if it correctly hides its implementation details and the user can ignore them. If there are hidden constraints on what a user can do with an object, but those are not enforced by the object, the object is an unsuccessful abstraction and a potential source of bugs.

Additionally, raw pointers are not dangerous.

Two words: "buffer overflow". C pointers lose size information.


Astonished that your comment got down-voted: it is one of the most insightful here and matches my experience with C++ rather well.

Mixing smart pointers and multi-threading in C++ may result in some nasty surprises that are very difficult to track down and would be impossible with garbage collection, and I'd be curious if Rust would be able to do better here with its fancy type system.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: