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

When the argument is that C++ has too many features that interact in unpredictable ways and are virtually impossible to get right, arguing that C++ is superior because it has more features is perhaps a fine argument in some hypothetical universe in which the primary objection to C++ is that it is missing features, but by failing to grapple with the points raised by the opposition in the real universe, you will fail to convince anybody. Everybody already knows all of these features, they're practically in the canonical Introduction to C++ pitch, and they still don't think C++ is great. Maybe you need to spend a bit more time listening more carefully to why; you certainly need to if you expect to talk anybody out of it.


What are some of these C++ features that interact in unpredictable ways? Just curious.


Implicit conversions come to mind. They don't need to interact with anything to be confusing.

Consider this program:

    #include <iostream>
    using std::cout;
    using std::endl;

    struct C {
        int x;
        C(int _x) : x(_x) {}

        operator bool() const { return 0 != x; }
    };

    struct D {
        float f;
        D(float _f) : f(_f) {}

        operator bool() const { return 0.0f != f; }
    };

    int main() {
        C c(9);
        D d(2.0f);

        if (c == d) {
            cout << "Equal" << endl;
        }

        return 0;
    }
g++ 3.4.4 doesn't so much as warn that something is fishy here, even with -Wall.

Not only that, but c and d are considered to be equal.


You don't get a warning because the program is doing exactly what you asked it to do. You said a C with x = 0 is equal to 'true'. And you said a D with f = 0.0 is equal to 'true'. By transitivity of equality ...


c and d are considered equal, you have overridden the boolean operators, what the code is actually calling on your if statement is:

c.bool() == d.bool()

In this case both will return true since they are non-zero, and thus the statement would be

1 == 1

Which is true; the compiler did exactly as you told it to do.


Maybe it's just coming from a dynamic language, but it appears that you've overridden the bool operators to always return true. (except when you pass in 0 and 0.0) If you redefine how two structs of different kinds are compared, who is the compiler to say it's a problem?


In most dynamic languages 0 is false and anything else is true but it normally wouldn't use that information to coerce two values of different types to booleans before comparing them.


I'm only aware of php and javascript equating 0 to false. But at any rate in this case it's not equating 0 to false, it's comparing non-zero to zero and returning true. (as it should)


In C, 0 evaluates to false.


In C++0x you can make those operator bool() explicit. Shouldn't have been there in the first place, and you still have to learn the difference between explicit and non-explicit operators, but at least now there is a way of making things behave.


Even if they were explicit it wouldn't have "solved" his issue. Since he is using them in an if statement the C++ compiler would have considered that an explicit conversion anyway in C++0x mode.

I don't have a C++0x compiler handy, or I would test it, but I do believe explicit is only meant for cases such as this:

a + 1;

where a has a bool() operator that returns 1 or 0, in the old mode if there was no way to get a to be a number it would look at the operator bool() see that it returns a number and use that. Using explicit on the bool() operator would make that illegal and most likely a compiler error.


Yes, several people have already piled on. But if the compiler didn't say "Equal", then I would be claim it's confusing/inconsistent.

Are you saying that the funtion YOU wrote to convert C/D to a bool shouldn't be invoked when YOU are using C/D as booleans?


It's perfectly logical to use those functions when comparing them as booleans.

But it's confusing that they're being used as booleans at all. They're converted because it will let the types match even though the conversion doesn't make much sense.


http://yosefk.com/c++fqa/defective.html isn't strictly limited to answering that question, but it touches on it a lot.

I know I'm flinging links around a lot here, but, well, this is all well-covered ground.


Most of the points mentioned in that particular link pertains why both C and C++ are inferior to languages like LISP and Python which have garbage collectors, weak type system and the like.

The bitching about bad compile time errors has been mostly fixed in clang.

Then only _inconsistency_ (in the correct sense of the term) in C++ I am aware of is the unordered initialization of static objects. So if you have "class A { ... A () { } };" and have a "A foo;" declared somewhere with static linkage, it can be hard to pin down exactly _when_ that constructor will be called. It will be called before control is transferred to main, but you may want even finer control.

If you have noticed other inconsistencies I'd love to know.


> The bitching about bad compile time errors has been mostly fixed in clang.

Yes, IOW, it is a compiler problem, not a language problem. Because one particular compiler is horrible on error presentation doesn't mean that the language is bad.

> declared somewhere with static linkage, it can be hard to pin down exactly _when_ that constructor will be called.

The language doesn't define it on purpose. The language leaves it to be defined by the implementation because it goes a little beyond the purpose of the compiler. The compiler transforms C++ source into object code. You can have multiple objects linked together into a single binary, and this linkage is very platform and operating-system dependent. C++ is already horribly difficult to implement correctly; if the language were to define an order for static initialization, it would be stepping on the operating system domain, and make it even more difficult to implement on some systems.


I guess that's why the Google C++ style guide lists using static non-POD types as a no-no. :)


often it's the implementation for certain platform that limits you, choices of what the C++ supports decides by the platform vendor - for example exceptions, rtti, or even up to date compiler.

another provblem arises due to the decoration, mangling of c++ symbols (while c externs do not have this problem), and sometimes this is problem even with two different versions of the same line of compiler

another one is the runtime incompabilities (exceptions again) and different compilers.

this problem is so bitchy, that if you have to develop plugin for maya, motion builder in c++, you have to use the same compiler the products were compiled with, which is not the case for a lot of the infrastructure, os out there...


Copy constructors are bad. Variable assignment should not be a user defined behaviour.




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

Search: