std::transform 返回的 std::pair 导致段错误

abb*_*bbe 2 c++ memory stl segmentation-fault c++11

我正在尝试将字符串向量转换为字符串对向量,但出现了段错误。我试图将其范围缩小到一个简单的测试用例(如下),并且我确信这可能与内存分配有关:

#include <string>
#include <vector>
#include <utility>

std::pair<std::string, std::string>
newP( const std::string& foo) {
  return std::make_pair(std::string("Foo"), std::string("Bar"));
}

int main()
{
  std::vector<std::string> vec;
  std::vector<std::pair<std::string, std::string>> pairs;

  vec.push_back("Hello, ");
  vec.push_back("World!");

  std::transform(vec.cbegin(), vec.cend(), pairs.begin(), newP);
}
Run Code Online (Sandbox Code Playgroud)

我在 FreeBSD 13.1 上遇到以下段错误:

Program received signal SIGSEGV, Segmentation fault.
Address not mapped to object.
0x0000000000205fd5 in std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__is_long (this=0x0) at /usr/include/c++/v1/string:1456
1456            {return bool(__r_.first().__s.__size_ & __short_mask);}
(gdb) bt
#0  0x0000000000205fd5 in std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__is_long (this=0x0) at /usr/include/c++/v1/string:1456
#1  0x0000000000205f0d in std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::__move_assign (this=0x0, __str="Foo") at /usr/include/c++/v1/string:2463
#2  0x0000000000205ee1 in std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::operator= (this=0x0, __str="Foo") at /usr/include/c++/v1/string:2485
#3  0x0000000000205ded in std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::operator= (
    this=0x0, __p=...) at /usr/include/c++/v1/__utility/pair.h:277
#4  0x0000000000203fe5 in std::__1::transform<std::__1::__wrap_iter<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const*>, std::__1::__wrap_iter<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >*>, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > (*)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)> (__first=..., __last=...,
    __result=..., __op=0x203c20 <newP(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)>) at /usr/include/c++/v1/__algorithm/transform.h:29
#5  0x0000000000203d96 in main () at pair.cc:19
Run Code Online (Sandbox Code Playgroud)

有人可以解释一下我做错了什么吗?如果可能的话,解决这个问题的最佳方法是什么?我对现代 C++ 相当脱节。

谢谢!

Som*_*ude 7

该向量pairs为空,pairs.begin()并将返回pairs.end()无法取消引用的迭代器。

将 的大小设置为与调用之前pairs相同的大小:vectransform

pairs.resize(vec.size());
std::transform(vec.cbegin(), vec.cend(), pairs.begin(), newP);
Run Code Online (Sandbox Code Playgroud)

已经提到的另一种方法是预分配内存,然后用于std::back_inserter附加到向量:

pairs.reserve(vec.size());
std::transform(vec.cbegin(), vec.cend(), std::back_inserter(pairs), newP);
Run Code Online (Sandbox Code Playgroud)

虽然reserve并非严格需要调用,但它将避免在向向量添加新元素时可能发生的额外重新分配和复制。

  • @Mehno 答案不必包含所有可能的解决方案才能被接受或投票。特别是关于这个问题,“resize”选项实际上比使用“back_inserter”更好(因为我们提前知道大小),因为使用“back_inserter”时可能会重新分配向量。 (3认同)