结构体按值传递会调用拷贝构造函数或逐成员位拷贝,生成独立副本,修改不影响原变量;纯POD类型安全高效,大结构体或含unique_ptr等资源管理成员时应避免,优先使用const T&传参。

结构体按值传递时会发生什么
结构体按值传递,本质是调用其**拷贝构造函数**(如果显式定义了)或执行**逐成员位拷贝**(默认行为)。这意味着函数内部操作的是原结构体的独立副本,修改它不会影响调用方的原始变量。
关键点:是否触发深拷贝,取决于结构体中是否包含指针、std::unique_ptr、动态分配资源等需要自定义管理的成员。纯 POD(Plain Old Data)结构体(如只含 int、double、数组、其他 POD 结构体)按值传递安全且高效。
什么时候不该按值传递
当结构体体积较大(比如超过 16–32 字节),按值传递会带来明显内存复制开销,尤其在频繁调用的函数中。编译器虽可能做 RVO 或拷贝省略(C++17 起保证某些场景下不调用拷贝构造),但不能依赖它消除所有开销。
- 常见误判:认为
struct Vec3 { float x, y, z; }很小,就无脑按值传——这没问题;但struct Mesh { std::vector<vertex> vertices; std::string name; }</vertex>就绝对不该按值传 - 隐式拷贝风险:若结构体含
std::shared_ptr,按值传只是增加引用计数,看似轻量,但语义上仍是“拷贝”;若含std::unique_ptr,则必须有可访问的拷贝构造(通常被删除),否则编译失败:error: use of deleted function 'std::unique_ptr<...>::unique_ptr(const std::unique_ptr<...>&)'</...></...>
如何安全地支持按值传递
确保结构体满足“可拷贝”要求:有可访问的拷贝构造函数、拷贝赋值运算符,且所有成员都可拷贝。对含资源管理的结构体,需显式定义这些函数并实现深拷贝逻辑(或明确禁止拷贝)。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
示例:一个带动态数组的结构体,若想支持按值传递,必须自己写拷贝构造:
struct Buffer {
int* data;
size_t size;
<pre class="brush:php;toolbar:false;">Buffer(size_t s) : size(s), data(new int[s]) {}
// 必须显式定义,否则默认位拷贝会导致 double-free
Buffer(const Buffer& other) : size(other.size), data(new int[other.size]) {
std::copy(other.data, other.data + size, data);
}
~Buffer() { delete[] data; }};
若不想支持拷贝,更推荐直接禁用:
struct NonCopyableBuffer {
NonCopyableBuffer(const NonCopyableBuffer&) = delete;
NonCopyableBuffer& operator=(const NonCopyableBuffer&) = delete;
// ... 其余成员
};
替代方案:什么时候该用 const 引用
绝大多数非 POD、或尺寸不确定的结构体,应优先使用 const T& 传参。它零拷贝、语义清晰(只读访问),且兼容临时对象(C++11 起延长生命周期)。
- 函数声明应写成:
void process(const MyStruct& s),而不是void process(MyStruct s) - 例外:函数内部**必然要修改副本**(比如做归一化、截断、格式转换),且不希望影响原值——这时按值传反而是最干净的设计,比手动
MyStruct copy = s;更直白 - 注意:不要返回局部结构体的引用(
const MyStruct& f() { MyStruct s; return s; }),这是悬垂引用
真正需要按值传递的场景其实不多:小而固定、语义上天然“值类型”的结构体(如 Point2D、RGBA、std::optional<t></t>),或者明确要隔离修改的场合。其余情况,const T& 是更安全、更通用的选择。

















