嵌套列表(字符串向量的向量)初始化失败

时间:2018-04-23 11:26:45

标签: c++ c++11 visual-studio-2017

此代码:

#include <vector>
#include <string>
#include <iostream>

class MyClass
{
public:
  MyClass(const std::vector<std::vector<std::string>> & v)
  {
    std::cout << "Vector of string vectors size: " << v.size() << "\n";

    for (size_t i = 0; i < v.size(); i++)
      std::cout << "Vector #" << i << " has size " << v[i].size() << "\n";
  }
};

int main()
{
  MyClass({ { "a" } }); // <--- ok
  MyClass({ { "a", "b" } }); // <--- PROBLEM
  MyClass({ { std::string("a"), "b" } }); // <--- ok
  MyClass({ { "a", "b", "c" } }); // <--- ok
  MyClass({ { "a" },{ "c" } }); // <--- ok
  MyClass({ { "a", "b" },{ "c", "d" } }); // <--- ok
}

输出(Visual Studio 2017):

Vector of string vectors size: 1
Vector #0 has size 1
Vector of string vectors size: 4
Vector #0 has size 97
Vector #1 has size 0
Vector #2 has size 0
Vector #3 has size 0
Vector of string vectors size: 1
Vector #0 has size 2
Vector of string vectors size: 1
Vector #0 has size 3
Vector of string vectors size: 2
Vector #0 has size 1
Vector #1 has size 1
Vector of string vectors size: 2
Vector #0 has size 2
Vector #1 has size 2

因此,它在所有情况下都可以正常工作,除非我们有一个向量的向量,包含两个字符串。如果我们从其中一个字符串文字显式构造std :: string,它也适用于上述情况。如果两者都只是普通的字符串文字,编译器似乎会“混淆”并构造一个包含4个项目的向量,第一个包含97个字符串。注意97是字符代码“a”。

我想我的问题是,如果编译器按照我的预期解释这个有问题的构造,还是这个错误的代码来初始化这样的嵌套列表?

3 个答案:

答案 0 :(得分:17)

MyClass({ { "a", "b" } })中的内部向量是使用范围构造函数创建的:

template <class InputIterator>
  vector (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type());

这是因为{ "a", "b" }被解释为std::initializer_list<std::string>而不是一对原始指针。

答案 1 :(得分:8)

进入调试器中的违规构造函数会发现VC ++选择了带有两个迭代器的lgb = LGBMRegressor(min_data=1)构造函数(在这种情况下它们是vector<vector<int>>。)
也就是说,它将构造视为

const char*

这当然会导致未定义的行为,因为这两个指针不属于同一个数组。

作为旁注,g ++编译了

std::vector<std::vector<std::string>> {"a", "b"}

但后者崩溃,而前者表现得像预期的那样。

VC ++以你期望的方式编译双支撑变量结构,所以我怀疑(希望)VC ++中存在一个错误。

答案 2 :(得分:0)

我找到了一种解决方法,有助于避免VC ++的这种未定义的行为。您可以像这样定义第二个构造函数:

MyClass(const std::vector<std::vector<int>> &)
{
}

然后,代码行会产生问题,

MyClass({ { "a", "b" } }); // <--- PROBLEM

将不再编译,并会给你“构造函数重载决议是模糊的”错误,指向问题。然后,您可以将文字类型转换为std :: string以解决问题。