Just for starters:
C++ has a broken and horribly outdated compilation model. Direct textual inclusion of files and find/replace model preprocessing is a horrible evil. It worked fine in the 70's and 80's, but it's the 21st century now, and we have much more powerful machines. Closely related is the horrific lack of consistent namespacing support (e.g. see the behavior of enums embedded in a namespace). It's far better than C, since it has namespacing in the first place, but compared to alternative languages like the .Net CLR family it's pretty weak. Using templates in large codebases is effectively hell because of the compilation model.
Those are largely historical artifacts, granted, but then so is the backwards compatibility to C. Although C++ never would have succeeded without it, that single point causes a huge amount of mess in the language itself. How many people properly cast rather than using C-casts, for instance? C-strings versus string classes? There's a lot of baggage here, and due to the compatibility arrangement, many many people think that C and C++ are related. Worse, they write C code and call it C++, which is misguided at best and fodder for extremely poor-quality software at worst.
C++ also slaughters one of the points that made C so elegant: consistency. There are several semantic interpretations of operators like &. Worse, the use of angle brackets for template parameters leads to well-known issues with conflicting over the bitshift operators. Overloading the bitshift operators for stream IO is just gross. Some blocks require semicolon termination for consistency with C (since C permits instantiating structs/etc. directly from the definitions) whereas others do not (namespaces, etc.). Object constructors/destructors violate the "has a return value" convention of every other executable block of code in the language.
C++ is a minefield of corner cases and obscure errata; you literally have to memorize the language spec to know how to use the language safely in many cases. Consider temporary-value semantics: do you actually know all the cases where temporaries may be instantiated according to the standard? Sure, most people beyond the hapless-newbie level know to prefer preincrement to postincrement in order to avoid temp/copy overhead, but what about temporaries introduced due to implicit type conversions? What about all the other corner cases I can't name because I myself haven't memorized them all?
Here's a fun exercise: read the C++ language spec, and count the number of times the phrase "undefined behavior" is mentioned. A common joke is that C++ has more undefined behavior than defined behavior. Uninitialized variables, the handling of incomplete types, hell the existence of the very notion of incomplete types (artifact of the compilation model), the ability to perform bogus casts (which are impossible to catch at compile-time!), the behavior of destructors vs. virtual destructors, misuse of placement new/manual destructor calls, member availability semantics in class constructors... I could go on.
There are plenty of other flaws in the language itself - problems with what is there. But the real killer is what C++ doesn't have: higher-order functions (function pointers are a miserably poor hack), reliable multiple dispatch, proper support for subtyping (not to be confused with subclassing), pattern matching, garbage collection... look at a more powerful language and there are scores of features that would be nightmarishly fragile if not outright impossible to replicate in C++. Even C# has outstripped C++ in power with the 2.0 inclusion of anonymous delegates, and this promises to improve still further in the 3.0 language revision. Ruby's consistency and potency puts C++ to shame, although it has its share of flaws. Then there's the real heavy-hitter languages: the Lisp family, the ML family (particularly OCaml), Haskell, Erlang...
C++ is crap. The only reason it persists is a combination of self-reinforcing market inertia and historical accident.