简体   繁体   中英

Defining a C++ conversion operator that doesn't return a value

In the following example, note A::operator B() does not return a value.

#include <stdio.h>

using namespace std;

struct B
{
    int valb;
    B(int x = 10) : valb(x) {
        printf("\nB::B()...\n");
    }
    B(const B& rhs) : valb(rhs.valb) {
        printf("\nB::B(const B&)...\n");
    }
    B(B& rhs) : valb(rhs.valb) {
       printf("\nB::B(B&)...\n");
    }
    void f() const {
        printf("\nB::f() const... [%d | 0x%x]\n", valb, this);
    }
    ~B() {
        printf("\nB::~B()...\n");
    }
};

struct A {
    static int gv;
    int *vala;
    A(int *x = &gv) : vala(x) {
        printf("\nA::A()...\n");
    }
    A(const A& rhs) : vala(rhs.vala) {
        printf("\nA::A(const A&)...\n");
    }
    void f() const {
        printf("\nconst A::f()...\n");
    }
    operator B () {
        printf("\nA::operator B()... [0x%x]\n", this);
        // return B();
    }
};

void func(const B& barg) {
    printf("\nfunc(const B&)...\n");
    barg.f();
}

int A::gv;

int main ()
{
    A a1;

    func(a1);

    return 0;
}

When built in rhel5 with g++ 4.5.2 (-std=gnu++0x -fno-elide-constructors), the following output is generated:

A::A()...

A::operator B()... [0x1cc30200]

func(const B&)...

B::f() const... [4196240 | 0x1cc30210]

B::~B()...

Note the 2 different addresses displayed indicate 2 different objects are being created.

Questions:

  1. Why isn't any B constructor invoked?

  2. Within func() , how is the B object over which B::f() is called, created?

  3. Shouldn't g++ have generated a compilation error?

  4. Is there any hint in the standard's Section 12.3.2 that would make the above output valid/expected?

The first thing is that it is undefined behavior, as the conversion operator is not returning anything.

Why isn't any B constructor invoked?

Because there is no B object created in the program.

Within func(), how is the B object over which B::f() is called, created?

It is not created. The program has undefined behavior, it is assuming that the reference refers to a B object, but there is no B object at that memory location (due to the failure to create it in operator B .

Shouldn't g++ have generated a compilation error?

With high enough warning and maybe some optimization level you would have got a warning. The standard does not require a diagnostic, so this is just quality of implementation.

Is there any hint in the standard's Section 12.3.2 that would make the above output valid/expected?

There is nothing that can make that expected , but it is clearly valid by the standard, since your program causes undefined behavior, whatever the compiler does and whatever you see happening is one valid incarnation of undefined behavior.

Falling off the end of a non- void function (other than main() ) without a return -statement is undefined behavior. Whatever happens is what you get. If you are lucky, you get a crash.

The reason it isn't an error is that the flow of control may never really end up falling off the end of a function but the compiler can't necessarily see that, eg

#include <stdexcept>

int f(int i) {
    if (i == 0) {
        throw std::runtime_error("index out of range");
    }
    return 17;
}

int g() {
    f(0);
    // compile-time error would be invalid
}

int main() {
    try { g(); }
    catch (std::exception const&) { }
}

In the above code the compiler could detect that f() never returns when called with 0 but if f() is coming from some library, it is generally impossible to predict.

You have Undefined Behavior in the conversion operator. Anything can happen, or not. Among the things that didn't happen in this particular case, was construction of a B.

Here is an equivalent program (for ordinary invocation with less than 55 arguments):

int main( int, char* argv[] ) { return *argv[55]; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM