繁体   English   中英

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

[英]Defining a C++ conversion operator that doesn't 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;
}

当使用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()...

请注意,显示的2个不同地址表示正在创建2个不同的对象。

问题:

  1. 为什么没有调用任何B构造函数?

  2. func() ,如何调用B::f()的B对象被创建?

  3. g ++不应该生成编译错误吗?

  4. 标准的第12.3.2节中是否有任何提示可以使上述输出有效/预期?

第一件事是它是未定义的行为,因为转换运算符没有返回任何东西。

为什么没有调用任何B构造函数?

因为程序中没有创建B对象。

在func()中,如何调用B :: f()的B对象被创建?

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

g ++不应该生成编译错误吗?

有足够高的警告和可能的优化级别,你会得到一个警告。 该标准不需要诊断,因此这只是实施的质量。

标准的第12.3.2节中是否有任何提示可以使上述输出有效/预期?

没有什么能作出这样的预期 ,但它是由标准的明确有效的,因为你的程序会导致不确定的行为,无论编译器,无论您看到的情况是不确定的行为的一个有效的化身。

在没有return陈述的情况下脱离非void函数(除main() )是未定义的行为。 无论发生什么,都是你得到的。 如果你很幸运,你会崩溃。

它不是一个错误的原因是控制流可能永远不会真正地从函数的末尾掉落但编译器不一定能看到,例如

#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&) { }
}

在上面的代码中,编译器可以检测到f()在使用0调用时永远不会返回,但如果f()来自某个库,则通常无法预测。

您在转换运算符中有未定义的行为 任何事情都可能发生或不发生。 在这个特殊情况下没有发生的事情是建造一个B.

这是一个等效的程序(对于少于55个参数的普通调用):

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

暂无
暂无

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

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