多文件C++项目中Undefined symbols链接错误的解决方法咨询
解决链接器错误:Undefined symbols for architecture x86_64
为什么会出现这个错误?
你的疑问问到了点子上:包含头文件并不会让链接器自动关联对应的实现文件,得先理清C++编译和链接的两个核心阶段:
- 编译阶段:每个
.cpp文件会被单独编译成目标文件(.o)。头文件(.h)的作用只是在编译当前.cpp时,提供类、函数的声明——告诉编译器“这个类/函数确实存在,你可以放心调用它”,但头文件里完全没有具体的实现代码。 - 链接阶段:链接器需要把所有用到的目标文件(比如
main.cpp.o和person.cpp.o)合并起来,找到每个函数调用对应的实现代码。如果某个函数的实现没有被编译成目标文件并加入链接过程,就会出现“符号未找到”的错误。
你的CMakeLists.txt里只指定了src/main.cpp作为源文件,person.cpp根本没被编译,所以链接器找不到Person::get_name()的实现代码,自然报错。
至于你直接包含person.cpp能运行,是因为此时person.cpp的代码被直接嵌入到main.cpp中一起编译了,但这是非常糟糕的编程习惯——会导致代码重复编译、违反封装原则,绝对不推荐这么做。
解决方法:修改CMakeLists.txt
只需要把person.cpp也添加到add_executable的源文件列表中,让CMake同时编译它:
cmake_minimum_required(VERSION "3.7.1") set(CMAKE_CXX_STANDARD 17) project("undirected_graph") # 将person.cpp加入源文件列表,让CMake编译它 add_executable(${PROJECT_NAME} src/main.cpp src/person.cpp )
如果你的person.h和person.cpp不在src目录下(比如和CMakeLists.txt同目录),就把路径改成person.cpp即可。
额外的代码bug提示
你的Person类构造函数有一个严重的内存安全问题:
Person(std::string &&n) : _name(&n), _address(nullptr) {}
这里n是右值引用,构造函数执行完毕后,n这个临时对象会被销毁,_name就变成了野指针,调用get_name()时会触发未定义行为(大概率程序崩溃)。而且你原来的析构函数delete _name也会崩溃,因为_name指向的是临时对象,不是用new分配的内存。
修复方法可以改成直接存储std::string对象,而不是指针:
// person.h #ifndef PERSON_H #define PERSON_H #include <string> class Person { public: Person(std::string n) : _name(std::move(n)), _address() {} // 改用值语义,去掉不必要的指针 void set_name(std::string name) { _name = std::move(name); } void set_address(std::string address) { _address = std::move(address); } std::string get_name() const { return _name; } std::string get_address() const { return _address; } private: std::string _name; std::string _address; }; #endif
这样既避免了内存泄漏和野指针问题,又简化了代码逻辑。
内容的提问来源于stack exchange,提问作者Niaz Ahsan
相关产品推荐
相关产品推荐

