开发者

What are the most surprising elements of the C++ standard?

I've decided to get more acquainted with my favorite programming language, but only reading the standard is boring.

What are the most surprising, counter-intuitive, or just plain 开发者_运维技巧weird elements of C++? What has shocked you enough that you ran to your nearest compiler to check if it's really true?

I'll accept the first answer that I won't believe even after I've tested it. :)


I found it somewhat surprising that

class aclass
{
public:
int a;
};

some_function(aclass());

will have ainitialized to 0 in some_function, while

aclass ac;
some_function(ac);

will leave it unitinitalized. If you explicitly define the default constructor of aclass:

class aclass
{
public:
aclass(): a() {}
int a;
};

then aclass ac; will also initialize a to 0.


Another answer I could add would be the throw() qualifier. For example:

void dosomething() throw()
{
   // ....
}

void doSomethingElse() throw(std::exception)
{
  // ....
}

Intuitively, this seems like a contract with the compiler, indicating that this function is not allowed to throw any exceptions except for those listed. But in reality, this does nothing at compile time. Rather it is a run-time mechanism and it will not prevent the function from actually throwing an exception. Even worse, if an unlisted exception is thrown, it terminates your application with a call to std::terminate().


The order of several declarators is actually unordered:

volatile long int const long extern unsigned x;

is the same as

extern const volatile unsigned long long int x;


Considering how unforgiving C++ usually is, I found it somewhat surprising that the standard actually allows you to delete null pointers.


Objects change type during construction.

In particular, when calling a virtual function from a constructor, you will not be calling the most derived override. Rather, you are calling the implementation from the class you're currently constructing. If that implementation happens to be 0 (pure virtual function), your program will crash at runtime.

A semi-real-world example:

class AbstractBase {
  public:
    AbstractBase() {
      log << "Creating " << className() << endl;
    }
  protected:
    virtual string className() const = 0;
}

class ConcreteGuy {
  protected:
    virtual string className() const { return "ConcreteGuy"; }
}

Upon constructing a ConcreteGuy object, the program will terminate with a "calling pure virtual function" error message.

This is why calling virtual functions from constructors is considered evil.


In C++ statements evaluate to something...

int main()
{
    "This is a valid C++ program!"
    "I will list the first five primes:";
    2;
    3;
    5;
    7;
    11;
}


It is not very well known that an array initiator may jump in index like in the enumeration definition.

// initializing an array of int
int a[ 7] = { [5]=1, [2]=3, 2};
// resulting in
int a[ 7] = { 0, 0, 3, 2, 0, 1, 0};

// initializing an array of struct
struct { int x,y; } ar[ 4] = { [1].x=23, [3].y=34, [1].y=-1, [1].x=12};
// resulting in
struct { int x,y; } ar[ 4] = { { 0, 0}, { 12, -1}, { 0, 0}, { 0, 34}};

// interesting usage
char forbidden[ 256] = { ['a']=1, ['e']=1, ['i']=1, ['o']=1, ['u']=1};

Most of these are true for C++ also.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜