gpt4 book ai didi

c++ - 如何使用带有右值引用参数的初始化程序//为什么不能用另一个 C 样式数组变量初始化 C 样式数组

转载 作者:太空狗 更新时间:2023-10-29 22:56:32 26 4
gpt4 key购买 nike

序言

在阅读本文之前,请注意我是 C++ 初学者。我还没有学习所有(基本)概念(例如模板),但我正在尝试在继续学习其他东西之前完全理解一些基础知识。

所以请不要提及 std::string 或 std:array、vectors、boost::arrays 以及它们对 C 风格数组的优越性。我确信他们是,但这不是这里的重点:)

我现在也认为有时更喜欢在 ctor 主体中分配元素而不是使用其成员初始值设定项列表。

我的问题

考虑以下示例。
当我必须定义一个复制构造函数来初始化在 main() 中声明的 character2 时,我注意到,在 Visual Studio 2017 中,IntelliSense 显示了 3 个不同的重载来初始化初始化列表中的类成员。例如,对于 'name' 变量,可用的列出重载是:

  • char [50](const char [50] &)
  • char [50](char [50] &&)
  • char [50]()


  • 附属问题1 :为什么 IntelliSense 仅在将变量声明为类成员时才允许显示这些重载? (如果在 main() 中声明,则 CTRL+SHIFT+SPACE 不会显示任何内容)

    最让我感兴趣的是其中包含右值引用的那个:
  • char [50](char [50] &&)对于“名称”变量
  • int [10](int [10] &&)对于“数据”变量
  • int(int &&) 'singledata' 变量

  • 现在,如果我使用 name()在初始化列表中,似乎使用了重载 #3。如果我使用 name("aaa") ,似乎使用了重载 #1。这让我开始研究其他概念:我现在了解左值、右值和左值引用的概念(但不是 this ,现在对我来说太复杂了),我无法完全理解右值引用的概念和移动语义。

    考虑到我的部分理解,我尝试在我的“参数化构造函数 2”中声明一个右值引用(然后它变成了一个“右值引用到 int”类型的左值)并用它来初始化“singledata”变量,希望能看到初始化器重载 #3 出现在 IntelliSense 中,但它没有。在这种情况下,似乎再次使用了带有左值引用参数(重载 #2)的那个。这是我无法解释的。

    所以我在这里,卡住了,这是我的 主要问题 1 : 什么时候带右值引用参数的初始化器碰巧用于类成员?

    主要问题 2 : 为什么不能使用另一个字符数组初始化一个字符数组,而可以使用字符串文字表达式?
    因为存在纯右值(prvalues)而变量最多只能转换为 xvalue 表达式?

    我知道这绝对不标准 ,但是如果我查看反汇编,则字符数组的初始化非常简单:
         2:     const char arrchar1[10]("hello");
    01142771 A1 38 9B 14 01 mov eax,dword ptr [string "hello" (01149B38h)]
    01142776 89 45 D8 mov dword ptr [arrchar1],eax
    01142779 66 8B 0D 3C 9B 14 01 mov cx,word ptr ds:[1149B3Ch]
    01142780 66 89 4D DC mov word ptr [ebp-24h],cx
    01142784 33 C0 xor eax,eax
    01142786 89 45 DE mov dword ptr [ebp-22h],eax

    堆栈分配的空间 [arrchar1] (在我的情况下是 [ebp-28h])在当前堆栈帧中只是由 MOV 填充指令集(实际上,在这种情况下为 2:为“ hell ”移动 1 个双字,然后为其余移动移动 1 个字),其中包含包含“hello”字符串文字的静态空间的内容。

    为什么没有 C++ 方式在编译后产生类似的东西,它会执行相同的事情,但“移动”堆栈分配空间(另一个数组变量)的内容,而不是“移动”一些静态内存?我希望是这样的: char arrchar2[10](arrchar1)
    示例:
    #include <string.h> // for strcpy

    class Character
    {
    public:
    //default constructor
    Character() {};

    //parameterized constructor 1
    Character(const char * pname) : // pointer to the string literal must be const (otherwise it is Undefined Behaviour)
    name(), data{ 1, 2, 3 } // mem-initializer-list:
    // - name is initialized with value-initialization (empty expression-list in a pair of parentheses following identifier)
    // - (C++11) data is initialized using list-initialization which becomes aggregate-initialization since it is an aggregate (array)
    {
    strcpy_s(name, pname);
    };

    //parameterized constructor 2
    Character(const char * pname, int &&val1) :
    name(), data{ 1, 2, 3 }, singledata(val1)
    {
    strcpy_s(name, pname);
    };

    //copy constructor
    Character(const Character & tocopy)
    // member initializer list

    //:name(), // >> IntelliSense shows 3 initializer overloads: char [50](const char [50] &) || char [50](char [50] &&) || char [50]()
    // >> (visible only if the array is declared in a class, no pop up in main...)

    : name("aaa"),

    //data() // >> IntelliSense shows 3 initializer overloads: int [10](const int [10] &) || int [10](int [10] &&) || int [10]()
    // >> (visible only if the array is declared in a class, no pop up in main...)

    data{ 1, 2, 3 }
    {
    // ctor body definition
    };
    private:
    char name[50];
    int data[10];
    int singledata;
    };

    void main()
    {

    Character character1("characterOne"); // the string literal has static storage duration (static memory), passed pointer allocated on stack memory
    Character character2(character1);
    Character character3("characterThree", 3);
    }

    最佳答案

    问题 1:

    我相信你在问为什么你的 singledata初始化不调用其 r 值初始化程序。简短的回答:因为你没有给它传递一个 r 值。

    在上面的构造函数中,参数 val1具有 r 值引用类型。但是,请记住,'r-valueness' 属性适用于表达式而不是类型。在初始化 singledata(val1) , 子表达式 val1是左值,即使变量 val1具有 r 值引用类型。它是由使某事物成为左值的规则定义的左值。顺便说一下,这些规则实际上只是一个条件列表,如果满足这些条件,表达式就会成为左值。粗略地说,你可以解释 val1这里是一个左值,因为它是一个可以获取地址的对象。

    您是否需要 singledata 的初始值设定项的 r 值引用版本? ,您将使用 singledata(std::move(val1))反而。这里的表达式 std::move(val1)具有 r 值类型,根据什么定义 std::move做。 singledata 中的右值引用因此构造函数可以绑定(bind)到它。

    关于c++ - 如何使用带有右值引用参数的初始化程序//为什么不能用另一个 C 样式数组变量初始化 C 样式数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47696006/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com