如何在字符串向量中获取指向字符串数据的指针?

时间:2018-08-30 18:09:52

标签: c++ c++11 auto

我有一个字符串向量作为我的主要数据容器。但是,为了与C库互操作,我需要能够将这些字符串视为字符数据指针(即const char*)。这听起来很简单,所以我写了一个这样的辅助类:

class strvecAccessor {
  const std::vector<std::string>& names;

public:
  strvecAccessor(const std::vector<std::string>& a) : names(a) {}
  size_t size() const { 
    return names.size(); 
  }
  const char* item(size_t i) {
    auto name = names[i];
    return name.data();
  }
};

此访问器类是短暂的。它用作现有字符串向量的包装,保证在此类的生存期内不会被修改或超出范围。下面是如何使用此类的一个示例:

void test(strvecAccessor& arr) {
  for (size_t i = 0; i < arr.size(); ++i) {
    printf("%s\n", arr.item(i));
  }
}

但是此代码中存在一个错误,该错误仅在我以--coverage -O0模式进行编译时才会出现,并且仅在Unix计算机上(我在C ++ 11兼容模式下使用CLang 6.0.0进行编译)才会显现出来。错误在于打印的字符串包含垃圾。

我相信会发生的事情是,name方法中的item()变量不是引用,而是数组的第i个元素的副本。它在item()函数的末尾超出范围,此时返回的指针会悬空。在大多数情况下,由于指针会立即使用,因此并不明显,但是在覆盖模式下,调用后立即将其填充其他数据。

如果我将auto name = names[i];替换为const std::string& name = names[i];,问题将消失。但是我真的不明白为什么,这是否真正解决了这个问题,或者只是将其深埋。所以我的问题是:为什么要用原始代码复制?以及将来如何保护自己免受此类错误的侵害?

1 个答案:

答案 0 :(得分:1)

const char* item(size_t i) {
    auto name = names[i];
    return name.data();
}

在这里,name是函数item()的局部变量,您将向该局部变量拥有的数据返回地址。当它超出范围(item()函数完成)时,name将被销毁。

由于要保证基础向量的生命周期,请尝试以下方法:

const char* item(size_t i) {
    return names[i].data();
}

这将是“安全的”,因为vector::operator[]返回对存储数据的引用,并且您不会像原始变量那样将多余的副本复制到name变量中。