当前位置: 首页 > 知识库问答 >
问题:

为什么我不能用l值初始化这个std::vector?

越雨泽
2023-03-14

我遇到了一个有趣的问题,我不明白发生了什么:

/* I WANT 6 ELEMENTS */
int lvalue = 6;

std::vector<int*> myvector { 6 }; /* WORKS FINE */
std::vector<int*> myvector{ lvalue }; /* DOESN'T WORK */
/* Element '1': conversion from 'int' to 'const unsigned __int64 requires a narrowing conversion */

据我所知,我提供的单个整数参数可以解释为使用参数size_typecount调用构造函数,也可以解释为使用初始化列表的构造函数。似乎只有当我提供左值时才调用initialiser_list构造函数,但当我提供r-valueint(至少是文字)时,size_tcount构造函数。为什么会这样?

这也意味着:

int num_elements = 6;
std::vector<int> myvector{num_elements};

结果仅为大小为1的向量;

std::vector<int> myvector(num_elements);

结果是一个大小为num\u元素的向量,但我认为应该避免这种初始化,因为偶尔会遇到最麻烦的解析问题。

共有1个答案

郭乐意
2023-03-14

让我们逐案看看发生了什么,以及为什么在使用左值时会出现上述缩小转换错误/警告。

在这里我们考虑:

int lvalue = 6; // lvalue is not a constant expression 

//---------------------------v------------------->constant expression so works fine
std::vector<int*> myvector { 6 };
std::vector<int*> myvector{ lvalue };
//--------------------------^^^^^^--------------->not a constant expression so doesn't work 

首先请注意,std::vector

因此,在这种情况下,将使用size\u t countctor。现在,让我们看看缩小转换错误/警告的原因。

当使用名为lvalue的变量而不是使用prvalueint时,我们得到错误/警告的原因是,在前一种情况下,lvalue不是一个常量表达式,因此我们有一个缩小的转换。这可以从dcl中看到。初始化。列表#7说明:

缩小转换是隐式转换

  • 从整数类型或无范围枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式,其值在整数升级后将适合目标类型

(重点矿山)

这意味着,从类型为int的左值(这是一个左值表达式)到向量的std::vector::vector(size\u t,/*其他参数*/)的size\u t参数的转换是缩小转换。但是从prvalue int到向量的std::vector::vector(size\u t,/*其他参数*/)参数的转换不是缩小转换。

为了证明确实如此,让我们看一些例子:

int main()
{
//----------------v---->no warning as constant expression
    std::size_t a{1};
    
    int i = 1;
//----------------v---->warning here i is not a constant expression
    std::size_t b{i};  

    constexpr int j = 1;
//----------------v---->no warning here as j is a constexpr expression
    std::size_t c{j};
    return 0;
}
struct Custom 
{
  Custom(std::size_t)
  {
      
  }
};
int main()
{
//-----------v---->constant expression
    Custom c{3}; //no warning/error here as there is no narrowing conversion
    
    int i = 3;  //not a constant expressoion

//-----------v---->not a constant expression and so we get warning/error
    Custom d{i}; //warning here of narrowing conversion here
    

    constexpr int j = 3; //constant expression 

//-----------v------>no warning here as j is a constant expression and so there is no narrowing conversion
    Custom e{j};  
    return 0;
}

演示

因此,该问题并不特定/限于std::vector,而是上述标准中引用的规则的结果。

在这里我们考虑:

std::vector<int> myvector{num_elements};//this uses constructor initializer list ctor 

在这种情况下,有一个构造函数初始值设定项list ctor可用于std::vector

另一方面,当我们使用:

std::vector<int> myvector(num_elements); //this uses size_t ctor

这里,将使用std::vector的大小向量,因为在这种情况下,初始值设定项列表向量甚至不可行,因为我们使用了括号。因此将创建一个大小为6的向量。您可以使用以下示例来确认这一点:

struct Custom 
{
   
  Custom(std::size_t)
  {
      std::cout<<"size t"<<std::endl;
  }
  Custom(std::initializer_list<int>)
  {
      std::cout<<"initializer_list ctor"<<std::endl;
  }
};
int main()
{
    Custom c(3);//uses size_t ctor, as the initializer_list ctor is not viable
    return 0;
}
 类似资料:
  • 今天我遇到了一个有趣的问题,是我自己打错的。我创建了一个lambda,它接受了对结构的引用,并错误地将其设置为按值接收参数的std::函数。 这里有一个更简洁的版本: 使用godbolt检查显示,使用MSVC编译成功,但对于Clang和GCC都失败了。 这是MSVC编译器中的bug吗?

  • 我想存储一组/值,但是s不一定是增量的,这意味着数据可以是: 因此,我试图创建一个c#等价的

  • 以下节目 使用当前Clang(12.0.0)编译,但不使用当前GCC(11.0.0 20201028)。使用GCC它会产生错误 根据[dcl.init.list/5]和string_view(char const*)构造函数是constepr这一事实,我假设Clang的行为就在这里。 对吗?

  • 为什么x没有在下面初始化? 平均而言,对于一半的迭代,for循环中的将是,从而初始化。对于另一半,找到的 循环替换为 同样糟糕。只有

  • 根据此堆栈溢出问题的公认(且唯一)答案, 使用 将改为零初始化对象。 那么,为什么呢?, 生成此输出: 定义的两个构造函数都是默认的?正当对于POD类型,默认初始化为零初始化。 根据这个问题的公认答案, 如果POD成员未在构造函数中初始化,也未在类初始化中通过C11初始化,则默认为已初始化。 不管是堆栈还是堆,答案都是一样的。 在C 98中(而不是之后),new int()被指定为执行零初始化。

  • 问题内容: 在调试器中,这些显示为。 如何避免这种情况? 问题答案: 这些精度问题归因于浮点数的内部表示,您无法做很多事情来避免它。 顺便说一句,至少在使用现代C ++编译器时,在运行时打印这些值通常仍会导致正确的结果。对于大多数操作而言,这并不是什么大问题。