返回铸造参考是否安全?

时间:2017-01-17 13:03:33

标签: c++ reference return-type

Point成为一个类,其实例可以显式地转换为wxPoint

class Point{
private:
    int x;
    int y;
public:
    explicit operator wxPoint() const
    {
        return wxPoint(x, y);
    }

    // More stuff
}

我有一个函数返回对Point类型对象的引用。这样一个函数的标题是:

const Point& GetPoint();

我的问题:定义以下Foo函数是否安全?

const wxPoint& Foo() const{
    return (wxPoint&) GetPoint();
}

首先,我使用Foo实现了return (wxPoint) GetPoint();,但是创建了一个新的(本地)对象,因此触发了有用的警告。此处显示的代码在没有警告的情况下编译。

我在这种类型的转换中找到的所有信息都是指继承的类,但这不是这种情况。

对于以这种方式投射参考时究竟发生了什么的解释将非常感激。

3 个答案:

答案 0 :(得分:16)

实际上您的转换运算符从未被调用过。您将从point返回对GetPoint实例的引用。之后您使用了C样式转换,在您的情况下将等同于reinterpret_cast<>(请参阅here)。您正在将对Point的引用转换为对wxPoint的引用,这两者是完全不相关的类型。另一方面,对返回引用的任何操作都是未定义的行为。

我的建议是始终使用C ++强制转换运算符。他们有好处:

  • 编译器检查C ++样式转换。
  • 可以轻松搜索C ++样式转换。
  • C ++样式转换表达了程序员的意图。

答案 1 :(得分:13)

其他答案已经解释了将Point&转换为wxPoint&只是对编译器起作用,告诉它引用绑定的对象是wxPoint对象,而不是真正。如果您尝试通过该引用访问wxPoint对象,则您的程序将具有未定义的行为,因为它未绑定到wxPoint对象。有时候当你骗到编译器时,它不会给你警告,只是要相信你没有做一些疯狂的事情。

修复是停止尝试返回对不存在的对象的引用:

wxPoint Foo() const {
    return GetPoint();
}

这将使用您的转化运算符构造wxPoint并按值返回,这是正常的。当没有任何内容可以绑定引用时,尝试通过引用返回是不行的。

答案 2 :(得分:4)

将引用转换为不相关的引用类型并不安全。虽然转换本身没有副作用,但通过另一种类型的引用访问原始对象具有未定义的行为(除非类型别名规则提供异常,就像它们在char的情况下那样但在此不适用因为标准没有为wxPoint)指定此类例外。

转换运算符不参与,没有任何区别。

  

对于以这种方式投射参考时究竟发生了什么的解释将非常感激。

&#34; C风格&#34; cast按优先顺序执行const_cast,static_cast或reinterpret_cast或其组合之一。没有static_cast适用于不相关的引用。

只有适用于将const Point&转换为wxPoint&的内容才是reinterpret_cast,后跟const_cast。 reinterpret_cast确实:

  

6)T1类型的左值表达式可以转换为对另一个类型T2的引用。结果是lvalue或xvalue引用与原始左值相同的对象,但具有不同的类型。没有创建临时,没有复制,也没有调用构造函数或转换函数。如果类型别名规则(见下文)

允许,则只能安全访问生成的引用
  

此处显示的代码在没有警告的情况下编译。

使用reinterpret_cast就像告诉编译器你知道你在做什么可能看起来像疯子一样,但不要担心,你知道你在做什么,所以不需要警告它。使用它应该非常小心。

由于C样式转换可能会隐式地重新解释,因此也需要非常小心。