Assertions à la Eiffel are often advocated, and in general considered good. Supporting them in C++ is surprisingly heavy and frustrating. It falls short of providing the same thing.
The old C assert macro is thus often considered a best compromise. The issue of the use of exceptions is related.
The problem with the assert macro, is that its effect is global, which means that it is not suitable for reusable code.
Assert is designed be used with the intention to remove it (by recompiling with NDEBUG) before delivery. The problem for reusable code, is that there is no delivery. This is the product/service dichotomy: reusable code is more of a service than of a product!
They are checked dynamically.
They often offer only an alternative for expressing the semantics of
types, to static typing (there are cases which can be expressed by
checkable assertions, and cannot be expressed statically through
types, but these are more infrequent than is commonly believed -out of
laziness! There are numerous cases which cannot be expressed by
either). A design using one strategy cannot be converted seamlessly
(e.g. without changing the users) into one using the other. In the
context of static typed object orientation (both Eiffel and C++), they
are thus a loss of orthogonality for a minor gain of expressivity.
Access control provides some, limited but static, support for
assertions.
Types do as well, especially if not restricted to being signature
specifications but extending up to behaviour specifications.