在分配与初始化期间键入安全性

时间:2017-07-03 12:04:47

标签: c++ c++11 type-safety

初始化列表语法的一个明显优势是它通过禁止narrowing conversions来提高类型安全性:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.kt.seekbar.MainActivity">

<TextView
    android:id="@+id/tv"
    android:layout_centerInParent="true"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<SeekBar
    android:id="@+id/seekBar"
    android:layout_centerInParent="true"
    android:max="100"
    android:layout_below="@id/tv"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />


</RelativeLayout>

但是,AFAIK无法在后续作业中强制执行相同的检查:

int x {7.9};   // error: narrowing
int y = 7.9;   // OK: y becomes 7. Hope for a compiler warning

为什么初始化期间的类型安全性在语言设计中比分配期间的类型安全更受关注?分配范围的缩小不太可能导致错误和/或更难检测到吗?

3 个答案:

答案 0 :(得分:3)

如果xint变量,那么

x = 7.9;
出于向后兼容性的原因,

必须继续在C ++ 11及更高版本中工作。即使x是大括号初始化的,也是如此。大括号初始化的int变量与非大括号初始化的int变量具有相同的类型。如果您通过引用传递x

void f(int& r);
f(x);
然后在f的正文中,没有办法告诉&#34;对象是否已经过括号初始化,因此语言不能对其应用不同的规则。

您可以通过以下方式防止缩小转化次数:

x = {7.9};  // error

您还可以尝试通过创建int&#34;包装器&#34;来利用类型系统。不允许缩小作业的类型:

struct safe_int {
    template <class T> safe_int(T&& x) : value{std::forward<T>(x)} {}
    template <class T> safe_int& operator=(T&& x) {
        value = {std::forward<T>(x)}; return *this;
    }
    operator int() const { return value; }
    int value;
};

不幸的是,在所有情况下,不能使这个类的行为像实际的int对象一样。

答案 1 :(得分:2)

  

为什么初始化期间的类型安全受到更多关注   语言设计比分配期间的类型安全性?

不,这不是原因,这是给你错误的列表初始化,例如,这也会出错:

int x = {7.8};

这是因为根据[dcl.init],列表初始化不允许缩小:

  

如果initializer子句是表达式和​​缩小转换   需要转换表达式,程序格式不正确。

答案 2 :(得分:0)

{}阻止转换类型,例如doubleint 但是

()可以执行此操作,只能显示有关转化的警告

你可以像这样写

int z(7.9) // == 7

你可以在确定时使用括号,在类中不存在std::initializer_list的构造函数,因为他将执行,或者你可以delete构造函数。