【问题标题】:std::vector constructor behaviorstd::vector 构造函数行为
【发布时间】:2011-10-08 22:15:38
【问题描述】:

取以下代码:

std::vector<std::vector<int>> v(10, 10);

此代码不能使用 libstdc++ 编译。但是,它确实可以使用 Visual Studio 的 C++ 库进行编译。我期望的行为是v 填充了 10 个大小为 10 的向量,这就是我使用 Visual Studio 得到的。

使用 Visual Studio 调用的构造函数是采用两个迭代器的构造函数。构造函数本身定义为:

template<class _Iter>
vector(_Iter _First, _Iter _Last)
    : _Mybase()
{   // construct from [_First, _Last)
    _Construct(_First, _Last, _Iter_cat(_First));
}

模板函数_Construct有两个版本。两者具有相同的签名,但一个从一个范围初始化向量,另一个用从第二个参数构造的值类型副本的 N 个副本初始化向量。在这种情况下,模板参数只对_Construct的第二个版本有效。

结果是v 填充了一个向量的 10 个副本,该向量是从值 10 构造的副本。通过像这样构造它采用相同的代码路径,因为您必须使用libstdc++:

std::vector<int> temp(10);
std::vector<std::vector<int>> v(10, temp);

这里哪个实现是正确的?这是 libstdc++ 错误还是 Visual Studio 的 C++ 库的扩展?

编辑:为了澄清,我不是在问它是否应该调用范围构造函数。我在问哪个 C++ 实现具有正确的行为,无论它采用哪条路径来实现它。

【问题讨论】:

  • 10 不是迭代器,我认为 VC++ 在这里是错误的,你得到正确的结果只是偶然。
  • 我不认为这是机会。被调用的_Construct 函数具有签名void _Construct(_Iter _Count, _Iter _Val, _Int_iterator_tag),因此看起来像是有意的。这两个_Construct 函数仅在构造函数中调用,也采用两个迭代器。
  • 你得到什么编译错误?此外,您可能希望在结束 &gt; 之间添加一个空格(即 std::vector&lt;std::vector&lt;int&gt; &gt; v(10, 10); 而不是 std::vector&lt;std::vector&lt;int&gt;&gt; v(10, 10); 以避免混淆编译器。
  • 错误:没有匹配函数调用'__cxx1998::vector>::_M_fill_initialize(__cxx1998::vector>::size_type, int&)'跨度>

标签: c++ standards-compliance msvcrt libstdc++ c++-standard-library


【解决方案1】:
std::vector<std::vector<int>> v(10, 10);

这不应该编译,因为向量的单参数构造函数是显式的。

C++03:

explicit vector(size_type n, const T& value = T(), const Allocator& = Allocator());

C++11:

explicit vector(size_type n);

这意味着像 10 这样的数字不能隐式变成大小为 10 的向量。

【讨论】:

  • 声明构造函数explicit 不会阻止vector 通过显式转换构造。在这种情况下,vector 由语句 _Ty _Newval = (_Ty)_Val 构造;由于它使用显式强制转换,即使_Valint,它也能够调用size_t 构造函数。
  • @dauphic:不过,在您到达这一点之前,您已经请求将第二个10 隐式转换为构造函数的第二个参数。显然,模板化范围构造函数绕过了这一点,这意味着我肯定会将其归类为错误/扩展。
  • 好的,我明白你的意思了。问题是对显式关键字的规避。有道理,谢谢。
【解决方案2】:

我期望的行为是 v 填充了 10 个大小为 10 的向量

这正是 GCC/libstdc++ 4.1.2 发生的事情。被调用的_Construct

void std::_Construct<std::vector<int>, int>(std::vector<int>*, int const&)

(省略分配器)。我无法告诉您标准对此有何规定,但我的直觉是,这是旧 GCC/libstdc++ 中的一个错误。

【讨论】:

  • 不,__CLIBCXX__ 定义为 20110929。可能是新版本或 gcc/clang 的错误。
猜你喜欢
  • 1970-01-01
  • 2013-12-08
  • 1970-01-01
  • 1970-01-01
  • 2012-11-03
  • 1970-01-01
  • 1970-01-01
  • 2018-03-12
  • 2012-07-10
相关资源
最近更新 更多