C++11 中访问指向 std::vector 中元素 n 的指针的标准方法是什么?
What is the standard way in C++11 to access the pointer to element n in a std::vector?
C++11 中访问指向元素 n 的指针的标准方法是什么 std::vector
?
vec.data() + n
或
&vec[n]
想到了。
"The standard way" 不存在,您的问题中的两种方式都可以正常工作,并且这里没有与性能相关的问题。但可能还有其他情况需要考虑:错误处理、静态分析警告、可能超载 operator &
、用不同类型替换 std::vector
的能力。
静态分析。当你使用第一个版本时,clang-tidy
throws
warning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic]
vec.data() + 1;
^
在你身上(当然前提是启用了这个特定的检查)。这不是最严重的问题,但为了完整起见,当您使用第二个版本时不会出现此警告。
将 std::vector
替换为另一种连续容器类型,或者如果您编写模板(您基本上希望对类型的要求尽可能小)。那么,
auto *ptr = vec.data() + n;
要求 .data()
成员函数存在并执行您期望它执行的操作。示例:Llvm 的 SmallVector
模板(针对较少的分配进行了优化)没有 data()
但它确实有 operator []
。我认为由于这个原因,
auto *ptr = &vec[n];
更可取。不可否认,另一种向量类型同样可以重载 operator()(...)
而不是 []
(或者根本没有重载运算符),但这可能比 .data() + n
方法更容易跨某些函数修复.
因此让我考虑以下两个问题的第二个版本。
错误处理:当你需要检查向量的大小是否至少为n + 1
:
auto *ptr = vec.size() > n ? &vec[n] : nullptr;
需要与 std::vector
本身的支票进行比较:
try {
auto *ptr = &vec.at(n);
// Do stuff with ptr
} catch (const std::out_of_range&) { /* ... */ }
这里哪个更好在很大程度上取决于特定于项目和上下文的情况(是否启用了异常,向量的大小是否是某些范围的先决条件等),因此通常 select一。了解这些选项是件好事。
超载operator &
。在应该在不同上下文中重用的代码中,这样做并没有什么坏处
auto *ptr = std::addressof(vec[n]);
因为这与此运算符的恶意重载配合得很好。
结合以上场景,选择最适合具体情况的方法。
C++11 中访问指向元素 n 的指针的标准方法是什么 std::vector
?
vec.data() + n
或
&vec[n]
想到了。
"The standard way" 不存在,您的问题中的两种方式都可以正常工作,并且这里没有与性能相关的问题。但可能还有其他情况需要考虑:错误处理、静态分析警告、可能超载 operator &
、用不同类型替换 std::vector
的能力。
静态分析。当你使用第一个版本时,
clang-tidy
throwswarning: do not use pointer arithmetic [cppcoreguidelines-pro-bounds-pointer-arithmetic] vec.data() + 1; ^
在你身上(当然前提是启用了这个特定的检查)。这不是最严重的问题,但为了完整起见,当您使用第二个版本时不会出现此警告。
将
std::vector
替换为另一种连续容器类型,或者如果您编写模板(您基本上希望对类型的要求尽可能小)。那么,auto *ptr = vec.data() + n;
要求
.data()
成员函数存在并执行您期望它执行的操作。示例:Llvm 的SmallVector
模板(针对较少的分配进行了优化)没有data()
但它确实有operator []
。我认为由于这个原因,auto *ptr = &vec[n];
更可取。不可否认,另一种向量类型同样可以重载
operator()(...)
而不是[]
(或者根本没有重载运算符),但这可能比.data() + n
方法更容易跨某些函数修复.
因此让我考虑以下两个问题的第二个版本。
错误处理:当你需要检查向量的大小是否至少为
n + 1
:auto *ptr = vec.size() > n ? &vec[n] : nullptr;
需要与
std::vector
本身的支票进行比较:try { auto *ptr = &vec.at(n); // Do stuff with ptr } catch (const std::out_of_range&) { /* ... */ }
这里哪个更好在很大程度上取决于特定于项目和上下文的情况(是否启用了异常,向量的大小是否是某些范围的先决条件等),因此通常 select一。了解这些选项是件好事。
超载
operator &
。在应该在不同上下文中重用的代码中,这样做并没有什么坏处auto *ptr = std::addressof(vec[n]);
因为这与此运算符的恶意重载配合得很好。
结合以上场景,选择最适合具体情况的方法。