【问题标题】:Better way to get the pointer of std::vector获取 std::vector 指针的更好方法
【发布时间】:2022-12-19 12:10:11
【问题描述】:

由于&v[0]v.data()提供了相同的方式来访问std::vector的底层指针,我想知道在稳定性和可移植性方面哪种方式是更好的选择?

【问题讨论】:

  • 由于std::vector 提供了一个data() 成员函数,我认为不需要手动获取第一个元素的地址。唯一“更好”的选择是出于可读性目的。 std::vector永远有下标运算符,它永远有一个data()成员,所以在稳定性和便携性方面选择哪个不是问题^^它们基本相同,并且都需要存在标准。
  • 唔。来自cppreference指针的范围是 [data(); data()+size()) 始终是有效范围,即使容器为空(在这种情况下 data() 不可取消引用)。不确定使用 &v[0] 时是否成立。
  • @AdrianMole 但是,如果您进一步观察,他们会提到如果向量为空,data() 可能会或可能不会返回 nullptr。我不确定他们的意思“有效的”范围。
  • @Fareanor 这里有一些讨论:stackoverflow.com/q/25419851/580083
  • 直到 data 保证有效。有了它,&v[0] 可以导致 UB,而 std::vector::data 保证返回有效的东西(尽管它的返回值是实现定义的)。似乎 data 是正确的方法......尽管在这两种情况下您仍然需要长度检查。

标签: c++ stdvector


【解决方案1】:

来自cppreference

返回值
指向底层元素存储的指针。对于非空容器,返回的指针等于第一个元素的地址
.

强调我的

对于非空的std::vectorv.data()&v[0] 比较相等。所以在这一点上,选择哪一个只是一个偏好问题。

但如果我们更仔细地看,我们也可以读到:

“返回指向用作元素存储的底层数组的指针。指针的范围是 [data(); data()+size()) 始终是有效范围,即使容器为空(在这种情况下,data() 不可取消引用)。”

强调我的

这意味着即使向量为空,您也可以使用任何标准算法处理迭代器,并使用 std::vector::data()(及其大小)返回的指针。
获取第一个元素的地址是不可能的,因为通过下标运算符 std::vector::operator[]() 访问空向量的值是未定义的行为。

知道这一点,我会说,使用std::vector::data() 是最好的选择。

【讨论】:

  • 旁注:当向量为空时,data() 可能会返回空指针值。在这种情况下,size() 为零,因此,data() + size() is well-defined 和 [data()data()+size()) 仍然是一个有效范围。
  • @j6t 是的,这正是我最后一段的重点。
  • @MarkB 为什么效率会降低?两者都是函数调用,data() 基本上只是返回托管指针。我什至希望data() 会快一点,因为不需要指针算法或指针取消引用。但是编译器优化可能会消除这种可能的差异。不管怎样,如果你关心性能,就把它剖析出来,否则,争论它毫无意义。什么是“最佳”取决于给定的标准,并且性能不在 OP 的列表中(但即使是,我怀疑它至少同样有效,甚至更快)。
【解决方案2】:

我尝试使用chat GPT 来回答您的问题。我没有答案,但如果它确实对你有帮助,你也可以考虑在那里提出未来的问题:

一般来说,最好使用data()成员函数来访问 std::vector 的底层指针,而不是使用 第一个元素上的寻址运算符 (&)。

更喜欢 data() 的原因之一是它更明确地说明了 意图访问向量的基础数据。它也更 便携,因为它适用于所有符合标准的实现 std::vector,而仅保证使用地址运算符 为 std::vector 这样的连续容器工作。

例如,需要 std::vector 来存储其元素 连续地存储在内存中,但不需要将它们存储在一个 单块内存。在某些实现中,std::vector 可以使用 一个小的缓冲区优化,用于存储小向量内联而不 分配堆内存。在这种情况下,使用 address-of 运算符 第一个元素不会产生指向元素开头的指针 向量使用的连续存储。

下面是一个示例,说明如何使用 data() 访问 std::vector 的基础数据:

 #include <vector>  
 #include <iostream>

 
 int main() {
     std::vector<int> v = {1, 2, 3, 4, 5};
  
     int* p = v.data();
     std::cout << "p[0] = " << p[0] << '
';
     std::cout << "p[1] = " << p[1] << '
';
     std::cout << "p[2] = " << p[2] << '
';
     std::cout << "p[3] = " << p[3] << '
';
     std::cout << "p[4] = " << p[4] << '
';
 
     return 0; 
 } 

输出:

p[0] = 1
p[1] = 2
p[2] = 3
p[3] = 4
p[4] = 5

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-02
    • 1970-01-01
    • 2016-02-19
    • 2011-09-23
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 2017-11-13
    相关资源
    最近更新 更多