检测const-reference的隐式类型转换

时间:2016-12-08 17:07:27

标签: c++ gcc reference

考虑这个例子:

#include <iostream>

struct Thing
{
    Thing(int const& ref) : ref(ref) {}
    int const& ref;
};

int main()
{
    int   option_i = 1;
    short option_s = 2;

    Thing thing_i(option_i);
    Thing thing_s(option_s);

    std::cout << thing_i.ref << "\n";   // 1
    std::cout << thing_s.ref << "\n";   // 2

    option_i = 10;
    option_s = 20;

    std::cout << thing_i.ref << "\n";   // 10
    std::cout << thing_s.ref << "\n";   // 2 <<< !!!
}

现在,我理解WHY就是这种情况:使用临时对象将short option_s转换为int。然后将对该临时值的引用传递给构造函数Thing::Thing,即等效于

// Thing thing_s(option_s);
int __temporary = option_s;
Thing thing_s(__temporary);

然而,在许多情况下这可能是不可取的,因为很难发现差异。 在这种情况下,临时至少还活着, 但这也很容易成为暂时的临时参考。

您是否知道有任何方法(设计模式,gcc编译器选项,静态分析工具或其他方法)来检测这种const-reference-to-temporary案例?

为了检测这种情况,你会牺牲常态吗?

2 个答案:

答案 0 :(得分:3)

只需编写另一个构造函数并将其标记为=delete

template<typename T>
Thing(T const &) = delete;

现在,如果你传递除<{1}}之外的任何参数,你将收到编译错误。

int

如果您只想删除 Thing thing_s(option_s); //error (或一组已知类型),那么您可以使用:

short

希望能给你一个基本的想法。

答案 1 :(得分:1)

为绑定引用的类定义构造函数的好方法是通过地址获取参数:

struct Foo
{
   Bar const & ref;
   Foo(Bar const * b) : ref(*b) {}
};

用法:

Bar x;
Foo y(&x);      // OK
Foo z(&Bar{});  // error: cannot take address of prvalue

这要求用户不遗余力地获取prvalue的地址,从而清楚地表明您期望已经存在的对象的地址,并且可能继续超过您的实例的生命周期。