【问题标题】:Template function that returns default constructed value返回默认构造值的模板函数
【发布时间】:2014-02-13 16:19:21
【问题描述】:

我有一个返回模板类型的默认构造值的函数:

template<typename T>
T do_stuff()
{
    return T();
}

我是这样使用的:

int main(int argc, char** argv)
{
    std::string str("hello");
    int a = 10;
    int *p = &a;

    str = do_stuff<std::string>();
    a = do_stuff<int>();
    p = do_stuff<int*>();

    return 0;
}

使用后我有:str 是一个空字符串,a eqauls 0 和 p 是一个空指针。 我可以理解为什么std::string 变量会变成一个空字符串(它具有构造一个空字符串的默认构造函数)。 但是为什么 int 变量变成 0 而指针变成空指针。 它是默认模板行为吗?

我在 Linux Centos 下使用 gcc 4.6.6。

【问题讨论】:

  • 这是应该发生的,作为它们的默认值。
  • T() 是值初始化,意思是基本类型的零初始化。
  • 不只是在模板中。

标签: c++ templates default-value


【解决方案1】:

因为T() 是值初始化,对于int 和指针类型(以及其他基本类型)是零初始化。

就像初始化一个 int 你会做的那样:

int x{};
int x = int();

//not initialized:
int x;   //if not at namespace scope
int x(); //method declaration

【讨论】:

    【解决方案2】:

    钥匙在里面

    //------vv
    return T();
    

    例如,你可以测试如下,这是等价的:

    int x =  int();
    std::cout << x;
    

    x 在这种情况下将始终为 0。指针也是如此——它是零初始化的,“制造”它NULL

    这是值初始化,由括号“引起”。

    【讨论】:

      【解决方案3】:

      来自this reference on value initialization

      • 如果 T 是具有至少一个用户提供的任何类型的构造函数的类类型,则调用默认构造函数。

      • 如果 T 是没有任何用户提供的构造函数的非联合类类型,则对象被初始化为零,然后调用隐式声明的默认构造函数(除非它是微不足道的)

        李>
      • 如果T是数组类型,则数组的每个元素都是值初始化的

      • 否则,对象被零初始化。

      发生的事情是上面列表中的最后一点。

      【讨论】:

        【解决方案4】:

        对于各个类型,这是正确的行为,无处不在。

        根据您是显式请求默认值(值初始化)还是不提及初始化(默认初始化),基元类型的初始化方式有所不同。

        如果构造原始类型而不提及初始化(这称为默认初始化),则值是随机的:

        int x;
        struct Y {
            int x;
        } x;
        int *x = new int;
        

        都是默认初始化,将包含随机值。

        但是如果你提到初始化器,它就变成了值初始化,并且值被初始化为适当的“零”(0 用于数字,0/nullptr 用于指针):

        int x = 0;
        int x = int();
        struct Y {
            int x;
            Y() : x() {} // the x() is important
        } y;
        struct Z {
            int x;
        } z = {};
        int *x = new int();
        

        都是值初始化,C++11增加了如下形式

        int x{};
        struct Y {
            int x;
            Y() : x{} {}
        } y;
        struct Z {
            int x;
        } z{};
        int *x = new int{};
        

        小心

        int x(); // function, NOT A VARIABLE
        

        它声明了一个不带参数并返回int的函数。这被称为“最令人头疼的解析”。

        【讨论】:

          【解决方案5】:

          这是在 c++ 11 标准第 8.5 节中定义的:

          对 T 类型的对象进行值初始化意味着:

          ——如果 T 是具有用户声明的构造函数 (12.1) 的类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是非良构的);

          ——如果 T 是没有用户声明的构造函数的非联合类类型,则 T 的每个非静态数据成员和基类组件都是值初始化的;

          ——如果T是一个数组类型,那么每个元素都是值初始化的;

          否则,对象被零初始化

          还有:

          默认初始化 T 类型的对象意味着:

          ——如果 T 是非 POD 类类型(第 9 条),则调用 T 的默认构造函数(初始化为 如果 T 没有可访问的默认构造函数,则格式错误);

          ——如果 T 是一个数组类型,每个元素都是默认初始化的;

          否则,对象被零初始化。

          还有:

          对 T 类型的对象进行零初始化意味着:

          ——如果T是标量类型(3.9),则将对象设置为0(零)转换为T的值;

          ——如果 T 是非联合类类型,则每个非静态数据成员和每个基类子对象都初始化为零;

          ——如果 T 是联合类型,则对象的第一个命名数据成员 89) 初始化为零;

          ——如果 T 是一个数组类型,每个元素都是零初始化的; — 如果 T 是引用类型,则不执行初始化。

          【讨论】:

            【解决方案6】:

            T() 是值初始化。

            用途:

            int x{};
            int x = int();
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-05-18
              • 2011-03-27
              • 1970-01-01
              • 1970-01-01
              • 2016-03-01
              • 1970-01-01
              • 2016-06-24
              • 2011-07-15
              相关资源
              最近更新 更多