C++投影:取STL容器数据成员的地址是否合法?
取std命名空间中STL容器数据成员的地址是否合法?
要回答这个问题,需要分两种情况明确界定:
1. 标准明确规定的公开数据成员:合法
如果STL类型的某个数据成员是C++标准强制要求公开提供的,那么取它的地址是合法且可移植的。
比如std::pair<T1, T2>的first和second成员,标准要求所有实现必须提供这两个公开非静态成员,因此直接取它们的地址完全合规。例如在C++20投影特性中的合法用法:
#include <algorithm> #include <vector> #include <utility> int main() { std::vector<std::pair<int, char>> items = {{1, 'x'}, {2, 'y'}, {3, 'x'}}; // 合法:&std::pair<int, char>::second是标准规定的公开成员指针 auto x_count = std::count_if(items.begin(), items.end(), [](char c) { return c == 'x'; }, &std::pair<int, char>::second); return 0; }
2. 容器的内部实现细节成员:非法(未定义行为)
对于std::vector、std::string、std::map这类通用容器,C标准没有规定它们的内部数据成员结构——比如存储元素的指针、大小计数器等成员的名称和布局,完全由各个标准库实现(如GCC的libstdc、Clang的libc++、MSVC的STL)自行决定,甚至不同版本的同一实现都可能修改这些细节。
直接取这类内部成员的地址,属于依赖未标准化的实现细节,会导致代码无法跨编译器、跨版本运行,是标准定义的未定义行为。例如:
// 非法:_M_start是libstdc++中std::vector的内部成员,标准未做规定 auto ptr = &std::vector<int>::_M_start;
总结
编写可移植的C++代码时,应始终依赖STL的公开接口(如begin()、end()、size()等成员函数,或标准规定的公开成员),而非容器的内部实现细节。只有当某个数据成员是标准明确要求存在的公开成员时,取其地址才是合法的。
内容的提问来源于stack exchange,提问作者A M
相关产品推荐
相关产品推荐

