向C++类构造函数传递大量数据的最优方式及惯用法问询
代码示例
1. Tester类
class Tester { public: int m_tester_value; Tester(){} Tester(int test_val) { m_tester_value = test_val; } Tester(const Tester & data) : m_tester_value(data.m_tester_value) { std::cout << "Tester Copied!" << std::endl; } Tester& operator=(const Tester & data) { m_tester_value = data.m_tester_value; return *this; } };
2. VectorTester类
class VectorTester { public: std::vector<Tester> m_vector; VectorTester(std::vector<Tester>* vector_construct) { if(vector_construct != nullptr) { m_vector = *vector_construct; } } VectorTester(const VectorTester & data) : m_vector(data.m_vector) { std::cout << "VectorTester Copied!" << std::endl; } };
3. TesterVectorGenerator函数
std::vector<Tester> TesterVectorGenerator(void) { std::vector<Tester> ret_vector; ret_vector.reserve(2); ret_vector.emplace_back(65); ret_vector.emplace_back(75); return ret_vector; }
4. 测试代码
int main() { std::vector<Tester> my_test_vector = TesterVectorGenerator(); VectorTester vector_test = VectorTester(&my_test_vector); for (const auto &i : vector_test.m_vector) { // access by value, the type of i is int std::cout << "VectorTester.m_vector:" << i.m_tester_value << std::endl; } for (const auto &i : my_test_vector) { // access by value, the type of i is int std::cout << "my_test_vector:" << i.m_tester_value << std::endl; } }
输出结果
Tester Copied! Tester Copied! VectorTester.m_vector:65 VectorTester.m_vector:75 my_test_vector:65 my_test_vector:75
问题解答
1. 指针传递是否是最优方式?
不是。你用指针传递后,依然要执行m_vector = *vector_construct的拷贝操作,最终的拷贝次数和直接传值完全一致。而且指针传递存在空指针风险,需要额外做nullptr检查,反而增加了代码复杂度。
指针本身占4/8字节(取决于32/64位平台)确实比整个vector小,但传递指针并没有减少后续的拷贝开销——因为你最终还是要把整个vector复制到类成员里。这种方式不仅不比传const引用更优,还更不安全。
2. C++中传递此类数据的标准惯用法
针对你需要复制vector到类成员的场景,常用三种方式:
方式一:传递const引用
这是最常规的写法,避免不必要的临时拷贝,同时保证不会修改原数据:
VectorTester(const std::vector<Tester>& vec) : m_vector(vec) {}
调用时直接传对象:VectorTester vector_test(my_test_vector);,和指针传递的拷贝次数相同,但代码更简洁安全,无需处理空指针。
方式二:移动语义(原vector不再使用时)
如果不需要保留原my_test_vector的内容,可以用移动构造直接转移原vector的资源,完全避免拷贝开销:
VectorTester(std::vector<Tester>&& vec) : m_vector(std::move(vec)) {}
调用示例:
// 直接用函数返回值构造,自动触发移动 VectorTester vector_test(TesterVectorGenerator()); // 主动转移原vector的所有权 VectorTester vector_test(std::move(my_test_vector));
这种方式不会触发Tester的拷贝构造(输出里不会出现"Tester Copied!"),效率最高。
方式三:构造函数内直接生成vector
如果vector的生成逻辑和VectorTester强绑定,可以把生成逻辑放到构造函数里,省去外部传递步骤:
VectorTester() { m_vector.reserve(2); m_vector.emplace_back(65); m_vector.emplace_back(75); }
额外代码优化建议
- Tester类的默认构造函数可以删掉(如果不需要默认构造对象),或者用
=default显式声明,符合现代C++风格。 - Tester的拷贝构造和赋值运算符无需手动实现,编译器生成的默认版本已经能完成int成员的拷贝;如果只是为了观察拷贝行为可以保留,否则建议删除以减少冗余代码。
- VectorTester的拷贝构造函数同理,编译器默认生成的版本已经能正确复制vector,日志仅用于调试时保留即可。
内容的提问来源于stack exchange,提问作者EmbeddedDOOD
相关产品推荐
相关产品推荐

