共计 2118 个字符,预计需要花费 6 分钟才能阅读完成。
从 sizeof 陷阱看原生数组的缺陷
刚学 C ++ 时,我写过这样的代码:

void printSize(int arr[]) {std::cout << "Array size:" << sizeof(arr) / sizeof(arr[0]); // 陷阱!}
int main() {int nums[] = {1,2,3,4,5};
printSize(nums); // 输出 8(指针大小)/4 = 2(错误)}
- 这里
sizeof(arr)返回的是指针大小(8 字节),而非数组总字节数 - 数组作为参数时会退化为指针,丢失长度信息
传统传参方式对比
1. int[] 语法糖
void process(int arr[], size_t len); // 等价于 int* arr
- 优点:写法简洁
- 缺点:
- 仍需额外传递长度参数
- 无法防止越界访问
2. 裸指针 int*
void process(int* begin, int* end); // 迭代器风格
- 优点:
- 明确传递范围
- 兼容 C 接口
- 缺点:
- 需手动检查空指针
- 无法直观看出数组长度
3. 数组引用 int(&)[]
template<size_t N>
void process(int (&arr)[N]) { // 保留数组长度
static_assert(N > 0, "Empty array");
}
- 优点:
- 自动推导数组长度
- 类型安全
- 缺点:
- 语法复杂
- 仅适用于静态数组
现代 C ++ 解决方案
std::array(编译期固定大小)
#include <array>
#include <stdexcept>
void safeProcess(const std::array<int, 5>& arr) {if (arr.empty()) throw std::invalid_argument("Empty array");
// 编译器保证不会越界
}
std::span(C++20 运行时动态大小)
#include <span>
void processChunk(std::span<int> data) {if (data.size() < 3) // 运行时检查
throw std::range_error("Need at least 3 elements");
for (int& val : data) { // 支持范围 for
val *= 2;
}
}
防御性编程技巧
编译期检查
template<typename T, size_t N>
void validateArray(const T (&arr)[N]) {static_assert(N <= 100, "Array too large");
static_assert(std::is_arithmetic_v<T>, "Numeric type required");
}
运行时边界检查
void safeAccess(std::span<int> arr, size_t idx) {if (idx >= arr.size()) {
throw std::out_of_range("Index"
+ std::to_string(idx) + "out of range");
}
arr[idx] = 42;
}
性能与内存考量
| 方案 | 栈内存 | 拷贝开销 | 长度安全 |
|---|---|---|---|
| 原生数组 | 低 | 高 | 无 |
| std::array | 中 | 中 | 有 |
| std::span | 低 | 低 | 有 |
- 小数组(<16 元素):优先用
std::array - 大数组或动态数据:用
std::span避免拷贝
避坑指南
多线程安全
std::mutex mtx;
void threadSafeProcess(std::span<int> data) {std::lock_guard<std::mutex> lock(mtx);
// 修改共享数组...
}
迭代器失效
void avoidInvalidation() {std::vector<int> vec{1,2,3};
auto it = vec.begin();
vec.push_back(4); // 可能使 it 失效
// 正确做法:操作前保存 end()迭代器}
思考与延伸
试着实现一个 SafeDynamicArray 类,要求:
1. 封装原生指针和大小
2. 支持范围检查
3. 提供迭代器接口
4. 禁止拷贝但允许移动
样例框架:
class SafeDynamicArray {
public:
explicit SafeDynamicArray(size_t size);
~SafeDynamicArray();
// 禁用拷贝
SafeDynamicArray(const SafeDynamicArray&) = delete;
SafeDynamicArray& operator=(const SafeDynamicArray&) = delete;
// 允许移动
SafeDynamicArray(SafeDynamicArray&& other) noexcept;
SafeDynamicArray& operator=(SafeDynamicArray&& other) noexcept;
int& operator[](size_t idx) {if (idx >= size_) throw std::out_of_range("...");
return data_[idx];
}
private:
int* data_;
size_t size_;
};
通过理解这些核心机制,希望你能更自信地处理 C ++ 中的数组参数传递问题。记住:现代 C ++ 的类型安全特性是你的好朋友!
正文完
