std::lock_guard<std::mutex> locker(m_mutex);
std::unique_lock<std::mutex> locker(m_mutex);
std::wstring_convert<std::codecvt_utf8<wchar_t>> strConvert; # C++17: codecvt_utf8 is deprecated
std::unique_ptr<EngineBase> srcEngine;
std::make_shared<SelectAreaRecognition>(selector, parent);
std::make_tuple(printerInfo, false);
最近一直在思考大型工程的维护。
// const 保证参数不会搞反。
char* strcpy(char* dest, const char* src) {
// 断言,Debug 版本生效。
assert((dest != NULL) && (src != NULL));
// 入参检查,特殊情况处理。
if (src == NULL || dest == NULL) return dest;
char* address = dest; // 功能逻辑
while ((*dest++ = *src++) != '\0')
NULL;
return address;
}
Flag fResizeMemory(void** ppv, size_t sizeNew) {
byte** ppb = (byte**) ppv;
ASSERT(ppb != NULL && sizeNew != 0);
#ifdef DEBUG
{
// 如果不是 realloc 扩大内存块时使原有存储位置发生移动这种现象很罕见。
// 如果某件事甚少发生的话,设法使其经常发生。
size_t sizeOld = sizeofBlock(*ppb);
/*
* 如果缩小,先把将被释放的内存空间填写上废料
* 如果扩大,通过模拟 realloc 的操作来迫使新的内存块产生移动
*(不让它在原有的位置扩展)如果新块和老块的长度相同,不做任何事情
*/
if (sizeNew < sizeOld)
memset((*ppb)+sizeNew, bGarbage, sizeOld-sizeNew);
else if (sizeNew > sizeOld) {
byte* pbNew;
if ( fNewMemory(&pbNew, sizeNew) ) {
memcpy(pbNew, *ppb, sizeOld);
FreeMemory(*ppb);
*ppb = pbNew;
}
}
}
#endif
byte* pbResize = (byte*) realloc(*ppb, sizeNew);
// ……
}
int ch = getchar();
。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
// 计算数组和指针的内存容量
char a[] = "hello world";
char *p = a;
cout << sizeof(a) << endl; // 12 字节
cout << sizeof(p) << endl; // 4 字节
// 数组退化为指针
void Func(char a[100]) {
cout << sizeof(a) << endl; // 4 字节而不是 100 字节
}
malloc 与 free 是 C++/C 语言的标准库函数,new/delete 是 C++ 的运算符。它们都可用于申请动态内存和释放内存。
反例:void* realloc( void* pv, size_t size );
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f(float x) { cout << "Base::f(float) " << x << endl; }
void g(float x) { cout << "Base::g(float) " << x << endl; }
void h(float x) { cout << "Base::h(float) " << x << endl; }
};
class Derived : public Base
{
public:
virtual void f(float x) { cout << "Derived::f(float) " << x << endl; } // 重载
void g(int x) { cout << "Derived::g(int) " << x << endl; }
void h(float x) { cout << "Derived::h(float) " << x << endl; }
};
int main()
{
Derived d;
Base* pb = &d;
Derived* pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); // Derived::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14
// Bad : behavior depends on type of the pointer
pb->g(3.14f); // Base::g(float) 3.14
pd->g(3.14f); // Derived::g(int) 3 (surprise!)
// Bad : behavior depends on type of the pointer
pb->h(3.14f); // Base::h(float) 3.14 (surprise!)
pd->h(3.14f); // Derived::h(float) 3.14
return 0;
}
关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。
void Foo(int x, int y);
// inline 是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。
inline void Foo(int x, int y) { // inline 与函数定义体放在一起
// …
}
对于任意一个类 A,如果不想编写上述函数,C++ 编译器将自动为 A 产生四个缺省的函数,如:
A(void); // 缺省的无参数构造函数
A(const A &a); // 缺省的拷贝构造函数
~A(void); // 缺省的析构函数
A& operator=(const A &a); // 缺省的赋值函数,如果包含成员类,会递归调用成员类的 赋值函数
内存泄漏:
String a("hello");
String b("world");
String c = a; // 调用了拷贝构造函数,最好写成 c(a);
c = b; // 调用了赋值函数
只要是可能被继承的类,析构都需要是虚的。 基类与派生类的析构函数应该为虚(即加 virtual 关键字)。
正常的 C++ 类都是派生类的析构执行后再自动执行基类的析构,如果析构不带 virtual 关键字,那么就不符合 C++ 类的标准行为,可能会导致基类的内存没有机会释放。
Review by 豪哥
编程精粹 Microsoft 编写优质无错代码的秘诀 (Writing Clean Code) 这本书的内容大多观点在微软编译器 debug & release 版本里面得到了实践。