C++ / Linux 学习 Day 2:引用、拷贝构造 与 auto.sh 自动编译脚本
日期:2025 年 10 月 31 日
学习主题:现代 C++ 语法进阶 + Linux 环境熟悉
今日关键词:引用、拷贝构造、浅拷贝与深拷贝、auto.sh 自动化脚本
一、现代 C++ 语法进阶
1. 左值引用与常量引用
代码示例
#include <iostream>
#include <string>
using namespace std;void print(const string &s) {cout << "打印: " << s << endl;
}int main() {string str = "Hello";print(str); // 传左值print("World"); // 传右值(通过 const 引用延长生命周期)
}
理解要点:
左值引用 (
T&):绑定到有名字、可取地址的变量。常量引用 (
const T&):可以绑定到临时对象(右值),并延长临时对象生命周期。"World"本是右值,不能直接绑定到普通引用上,但 可以绑定到 const 引用,因此合法。
常见错误
一开始报了很多奇怪的链接错误:
undefined reference to `std::cout' ...
原因是:
使用了
gcc来编译 C++ 代码。
解决方法:
改用 g++:
g++ cite.cpp -o cite
gcc 是 C 编译器,
g++ 才会自动链接 C++ 的标准库(std)。
2. 函数参数传递方式
练习内容
实现三个版本的 swap:
值传递
引用传递
指针传递
理解差异:
| 方式 | 是否改变实参 | 效率 |
|---|---|---|
| 值传递 | 不会改变原值 | 较慢 |
| 引用传递 | 直接操作原变量 | 推荐 |
| 指针传递 | 可为空指针 | 稍复杂 |
3.构造函数与析构函数
代码示例
#include <iostream>
using namespace std;class Point {
public:int x, y;Point() : x(0), y(0) { cout << "默认构造" << endl; }Point(int x, int y) : x(x), y(y) { cout << "有参构造" << endl; }~Point() { cout << "析构" << endl; }
};int main() {Point a; // 默认构造Point b(3, 4); // 有参构造Point c(b); // 拷贝构造(编译器自动生成)
}
理解要点:
即使你不写拷贝构造,编译器也会自动生成一个 浅拷贝版本。
所以:
Point e = b;会自动调用隐式拷贝构造函数,并复制成员变量值。
出错反思:
“为什么我注释掉拷贝构造函数之后还能拷贝?”
因为编译器会自动合成一个默认拷贝构造函数,
行为是成员逐一复制(浅拷贝)。
4. 深浅拷贝区别
实验代码
#include <iostream>
#include <cstring>
using namespace std;class MyString {
private:char* data;
public:MyString(const char* str = "") {cout << "构造: " << str << endl;data = new char[strlen(str) + 1];strcpy(data, str);}// 深拷贝MyString(const MyString& other) {cout << "拷贝构造" << endl;data = new char[strlen(other.data) + 1];strcpy(data, other.data);}~MyString() {cout << "析构: " << data << endl;delete[] data;}
};
输出分析
构造: hello
拷贝构造
析构: hello
析构: hello
如果不用深拷贝,会出现 重复释放内存(double free) 错误。
解决方案
1. 改写拷贝构造函数为“深拷贝”;
2.或使用智能指针 shared_ptr<char[]> 管理资源;
3. 移动构造时要把源指针置 nullptr,防止析构时重复释放。
5. 运算符重载与 this 指针
示例:赋值运算符重载
Vec2& operator=(const Vec2& rhs) {if (this != &rhs) { // 防止自赋值x = rhs.x;y = rhs.y;}return *this; // 返回当前对象的引用
}
理解:
this→ 指向左操作数对象;rhs→ 右操作数;return *this让语句支持链式调用a = b = c;。
验证:
cout << &a << endl;
cout << &b << endl;
打印结果中,this == &a,rhs == &b。
二、Linux 环境熟悉
1. 基本命令回顾
| 命令 | 功能 |
|---|---|
cd | 切换目录 |
ls -l | 查看文件详细信息 |
mkdir | 新建目录 |
rm -rf | 删除文件/目录 |
chmod +x | 添加可执行权限 |
./file | 执行程序 |
2.Shell 脚本 auto.sh
最终脚本
#! /bin/bash# 检查当前目录是否有 .cpp 文件
if [ ! -e *.cpp ]; thenecho " 没有找到任何 .cpp 文件!"exit 1
fi# 清理旧的可执行文件
if [ -f main ]; thenecho "clear"rm -f main
fiecho "bianyi"
g++ *.cpp -o mainif [ $? -eq 0 ]; thenecho "success"./main
else echo "failture"
fi
功能说明
| 符号 / 命令 | 含义 |
|---|---|
-f | 文件是否存在且为普通文件 |
-e | 文件是否存在(文件或目录均可) |
$? | 上一条命令的返回值(0 表示成功) |
-eq | 判断数值是否相等 |
rm -f | 强制删除文件,不提示 |
chmod +x | 给脚本添加可执行权限 |
运行效果
clear
bianyi
success
Hello Linux!
出错与解决记录
| 错误信息 | 原因 | 解决方法 |
|---|---|---|
Permission denied | 文件没有执行权限 | chmod +x auto.sh |
syntax error near unexpected token 'then' | 缺少空格,如 if[! -f main.cpp];then | 改成 if [ ! -f main.cpp ]; then |
undefined reference to std::cout | 用 gcc 编译 C++ | 改用 g++ |
collect2: error: ld returned 1 exit status | 链接失败(少加源文件) | 改成 g++ *.cpp -o main |
三、学习成果总结
掌握了:
左值 / 右值 / 常量引用 的使用场景;
构造函数、拷贝构造、析构函数的执行顺序;
深拷贝与浅拷贝区别;
运算符重载的原理与
this指针;Linux 文件系统与权限命令;
Shell 条件判断与自动化脚本。
实战完成:
auto.sh自动化编译运行脚本;成功运行多文件项目;
熟悉终端命令 + vim 编辑。
