简体   繁体   English

定义不返回值的C ++转换运算符

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

In the following example, note A::operator B() does not return a value. 在以下示例中,注意A::operator B()不返回值。

#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: 当使用g ++ 4.5.2(-std = gnu ++ 0x -fno-elide-constructors)在rhel5中构建时,会生成以下输出:

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. 请注意,显示的2个不同地址表示正在创建2个不同的对象。

Questions: 问题:

  1. Why isn't any B constructor invoked? 为什么没有调用任何B构造函数?

  2. Within func() , how is the B object over which B::f() is called, created? func() ,如何调用B::f()的B对象被创建?

  3. Shouldn't g++ have generated a compilation error? g ++不应该生成编译错误吗?

  4. Is there any hint in the standard's Section 12.3.2 that would make the above output valid/expected? 标准的第12.3.2节中是否有任何提示可以使上述输出有效/预期?

The first thing is that it is undefined behavior, as the conversion operator is not returning anything. 第一件事是它是未定义的行为,因为转换运算符没有返回任何东西。

Why isn't any B constructor invoked? 为什么没有调用任何B构造函数?

Because there is no B object created in the program. 因为程序中没有创建B对象。

Within func(), how is the B object over which B::f() is called, created? 在func()中,如何调用B :: f()的B对象被创建?

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 . 程序具有未定义的行为,假设引用引用B对象,但该内存位置没有B对象(由于无法在operator B创建它)。

Shouldn't g++ have generated a compilation error? g ++不应该生成编译错误吗?

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? 标准的第12.3.2节中是否有任何提示可以使上述输出有效/预期?

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. 在没有return陈述的情况下脱离非void函数(除main() )是未定义的行为。 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. 在上面的代码中,编译器可以检测到f()在使用0调用时永远不会返回,但如果f()来自某个库,则通常无法预测。

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. 在这个特殊情况下没有发生的事情是建造一个B.

Here is an equivalent program (for ordinary invocation with less than 55 arguments): 这是一个等效的程序(对于少于55个参数的普通调用):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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