cs106l assignment 2025spring
assignment5 treebook
Part 1: Viewing Profiles
分析
就一个要求,编写一个将 User 打印到 std::ostream operator<< 方法,即重载运算符<<(此运算符应在 user.h 中声明为友元函数)
要求的效果
User(name=Alice, friends=[Bob, Charlie])
实现
首先在user.h中声明
friend std::ostream& operator<<(std::ostream& os, User& user);
在user.cpp中实现
std::ostream& operator<<(std::ostream& os, User& user){
os<<"User(name="<<user.get_name()<<", friends=[";
std::string* friends = user._friends;
size_t size = user.size();
for(size_t i = 0; i < size; ++i){
if(i+1 < size){
os<<friends[i]<<", ";
}else{
os<<friends[i];
}
}
os<<"])";
return os;
}
一些细节
为什么是引用 (&) 而不是值?
禁止拷贝:std::ostream 是禁止复制的(拷贝构造函数被删除)。
效率:返回引用避免不必要的拷贝开销。
修改原始流:需直接操作原始流对象(如 std::cout),而非其副本。
Part 2: Unfriendly Behaviour
为 User 类实现我们自己的特殊成员函数 (SMF) 版本,并删除一些编译器生成的版本无法满足要求的函数。
1.为 User 类实现析构函数。为此,请实现 ~User() SMF
成员变量
private:
std::string _name;
std::string* _friends;
size_t _size;
size_t _capacity;
_friends 是动态分配的资源:
_friends 是 std::string* 类型,指向通过 new[] 动态分配的字符串数组(从析构函数的 delete[] 可以推断)。这类动态分配的内存不会被编译器自动释放,必须手动通过 delete[] 回收,否则会导致内存泄漏。其他成员无需手动释放。
User::~User(){
delete[] _friends;
};
在 C++ 中,析构函数用于对象销毁时释放资源。以下情况需要手动重写析构函数:
1.类中包含动态分配的内存(new/new[] 分配)
- 当类成员是通过 new 分配的单个对象,或 new[] 分配的数组(如 std::string* _friends),必须在析构函数中用 delete 或 delete[] 释放,否则会导致内存泄漏。
2.类持有文件句柄、网络连接等系统资源 - 如打开的文件指针(FILE*)、网络套接字(socket)、数据库连接等,这些资源不会被默认析构函数自动释放,需在析构函数中显式关闭或释放(如 fclose()、close())。
3.类使用了其他需要手动释放的资源 - 例如动态申请的共享内存、互斥锁、图形库资源等,需在析构函数中调用对应的释放函数(如 munmap()、pthread_mutex_destroy())。
4.类继承体系中存在虚函数 - 若基类可能被继承,且派生类可能有动态资源,基类需定义虚析构函数(virtual ~ClassName()),否则删除基类指针时可能不会调用派生类的析构函数,导致资源泄漏。
不需要重写析构函数的情况:
- 类成员均为基本类型(int、size_t 等)或标准库类型(std::string、std::vector 等),这些类型会自动管理资源,默认析构函数足够。
- 类没有动态分配的资源或系统资源,仅通过成员对象的析构函数即可完成所有清理。
核心原则:当类需要手动管理资源(即资源的分配和释放不由编译器或标准库自动处理)时,必须重写析构函数。
2.使 User 类可进行复制构造。为此,请实现 User(const User& user) SMF
User::User(const User& user):_name(user._name),
_size(user._size),
_capacity(user._capacity),
_friends(nullptr)
{
if (_capacity > 0) {
_friends = new std::string[_capacity];
for (size_t i = 0; i < _size; ++i) {
_friends[i] = user._friends[i];
}
}
}
直接复制 _name(std::string 自带深拷贝,无需手动处理)、_size 和 _capacity 的值。
关键:为新对象的 _friends 重新分配一块内存(new std::string[_capacity]),而不是直接复制原对象的 _friends 指针(这是与浅拷贝的核心区别)。
3.实现 User& operator=(const User& user) SMF
User& User::operator=(const User& user){
// 1. 自赋值检查:如果是自己赋值给自己,直接返回
if(this == &user){
return *this;
}
// 2. 释放当前对象的旧资源(避免内存泄漏)
delete[] _friends;
//3. 复制基本成员和容量信息
_name = user._name;
_size = user._size;
_capacity = user._capacity;
_friends = (_capacity > 0) ? new std::string[_capacity] : nullptr;
for(size_t i = 0; i < _size; ++i){
_friends[i] = user._friends[i];
}
return *this;
}
4.删除 User(User&& user) SMF/User& operator=(User&& user) SMF
User(User&& user) = delete;
User& operator=(User&& user) = delete;
Part 3: Always Be Friending
重载operator+=
User& User::operator+=(User& rhs){
this->add_friend(rhs.get_name());
rhs.add_friend(this->get_name());
}
重载 operator<
bool User::operator<(const User& rhs) const{
return this->get_name() < rhs.get_name();
}

浙公网安备 33010602011771号