bug记录—C++学习笔记
记录一下lab里遇到的错误。
1.类
1. 常量成员只能通过初始化列表初始化。
2. 同名的常量成员函数与非常量成员函数不同。
class Student { // TODO: implement class Student. private: const std::string name; const std::string year; protected: public: const std::string id; std::string toString() const; Student(const std::string id, const std::string name, const std::string year) :id(id), name(name), year(year) {}; virtual double getGpa() const=0; virtual double getAvgScore() const=0; };
以下没有实现getGpa和getAvgScore函数:
class Graduate:public Student{ public: Graduate(const std::string id, const std::string name, const std::string year) : Student(id,name,year) {}; double getGpa() { return 0.0; }; double getAvgScore() { return 0.0; }; };
且声明和实现时都要加const。
2. 函数 / 语句
2.1 cout
调整小数位数(之前一直在用printf)
cout << setiosflags(ios::fixed); cout << setprecision(2); //输出两位小数
强制清空缓冲区
cout.flush();
cout << a << flush;
2.2 try catch
2.3 assert
assert的用法为 assert(表达式); 如果表达式为真,程序继续运行;如果为假,程序停止并返回报错信息。
关于报错信息,chatGPT的说法是:
报错信息是assert自动生成的,无法被人为更改。以下是一个报错信息的例子: Assertion failed: (x == 0), function main, file example.cpp, line 5.
但是可以通过自定义自己的断言宏,修改报错信息。
2.3.1 NDEBUG
一般来说,assert用于在debug阶段调试。如果定义了NDEBUG宏,assert将被编译器忽略(一般在发布的终产品中使用)。
可以按以下方式(?)定义NDEBUG宏:
g++ -DNDEBUG my_program.cpp
也可以在C++代码中直接定义:
#define NDEBUG #include <cassert> int main() { int x = 10; assert(x > 0); // 虽然这里的条件为真,但由于定义了NDEBUG宏,所以这个断言会被忽略 assert(x == 0); // 同样,由于定义了NDEBUG宏,所以无论条件真假,这个断言都会被忽略 return 0; }
3.指针—函数指针
4.文件输入输出
4.1 输入输出流
ofstream在尝试打开文件时,如果文件不存在会创建文件。
如果不使用C++17并且希望检查文件是否存在,可以
std::ifstream testFile("../"+filename); if(!testFile){ std::cout << "? Filename not specified" << std::endl; return; } testFile.close(); std::ofstream file("../"+filename);
另外file和testFile不能重名。
5.指针与所有权
对于所有权,chatGPT的解释是:所有权定义的是谁负责管理这个资源对象,通常来说,"所有权"是谁应该负责调用对象的析构函数和释放资源。
5.1 RALL
chatGPT:
在 C++ 中,RAII 是 "Resource Acquisition Is Initialization"(资源获取即初始化)的缩写,它是一种编程技巧,用于管理,尤其是自动管理,如内存,文件句柄,锁等资源的生命周期。这种技巧是通过将资源的生命周期与某个对象的生命周期绑定,保证对象在其构造函数中申请分配资源,并在析构函数中释放资源。使用 RAII 技巧,可以在大部分情况下避免内存泄漏和其他由于手动资源管理而产生的问题。
没看懂
5.2 unique_ptr
"unique_ptr"是C++11引入的一种智能指针,它表示"唯一"所有权,即一次只能有一个"unique_ptr"拥有某块内存。当unique_ptr被销毁(例如离开其作用域)时,它所管理的对象也就自动被销毁。
基础的使用方式如下:
// p是指向内存块的指针,内存块的值为1 UniquePtr<int> p = MakeUnique<int>(1); // p2也想要指向指针p所指向的内存块,引发编译错误 UniquePtr<int> p2 = p; // compile error // p将⾃⼰所有的内存块移动给p3,p变成nullptr, p3成为内存块的所有者 UniquePtr<int> p3 = std::move(p);
unique_ptr还使用了RALL,避免手动的 new 和 delete 。
{ UniquePtr<int> p = MakeUnique<int>(1); fn(p); // 对p及指向的内存进⾏操作 } // p的⽣命周期结束,内存⾃动被释放
(两段代码来自lab 3)