记笔记,很久没认真学习了,被别人一考就不行了,特别是一些细节,打算以后搜集一些细节的问题
1、#pragma pack(n) 的作用?
n 为1, 2, 4, 8, 16任意值,表示字节对齐,适用于通信、不同CPU的二进制兼容,许多单位喜欢面试该提
例:
#pragma pack(1)
struct{ char c; long ld;};//sizeof :char(1) + long(4) = 5
#pragma pack() //恢复原来设置
#pragma pack(2)
struct{ char c; long ld;};//sizeof :char(1)(pack(2)导致+1对齐) + long(4) = 6
#pragma pack(4)
struct{ char c; long ld;};//sizeof :char(1)(pack(4)+3对齐) + long(4) = 8
#pragma pack(8)
struct{ char c; long ld;};//sizeof :char(1)(pack(8)超过最长类型long的字节数按照pack(4)+3对齐) + long(4) = 8
如果是
#pragma pack(8)
struct{ char c; double d;};//sizeof :char(1)(pack(8)+7对齐) + double (8) = 16
2、C++的虚函数继承中子类相同函数名不加virtual 关键字还有多态性吗?
class A{ public : virtual void f();};
class B : public A{public : void f();};
A*p = (A*)new B();
p->f();//这里还有多态性,调用B::f();
3、构造函数、析构函数调用虚函数有多态性吗?
构造函数调用虚函数将丧失多态性,析购函数调用虚函数还有多态性。
4、智能指针的释放问题?
智能指针一般不需要自己释放,但是有的时候总是会有释放相关的错误:
如:我曾经这样释放
CComPtr<***> Ptr;
Ptr->Release();
这样会产生错误,因为CComPtr在析构时将在释放一次,就会产生内存访问错误;
正确的做法是Ptr.Release(); "." 和->的区别,注意,因为这里牵涉到AddRef()的应用计数,这样释放CComPtr才会知道已经被释放了,不需要在析构里释放;
我曾经写过这样的函数
void f()
{
::CoInitialize(NULL);
CComPtr<IUnknown> IUPtr;
/*
do someing;
*/
::CoUninitialize();
}
这里我以为智能指针可以自己释放,就没有.Release();谁知道CComPtr在函数里生命周期比::CoUninitialize();要长,实际的语句运行顺序是
::CoUninitialize();
CComPtr::~CComPtr();
这里CComPtr析构函数要在CoUninitialize之后运行,COM都被释放了,COM智能指针再释放当然会出错了;
所以我们要保证::CoUninitialize();最后运行,在所有与COM相关的类的生命周期结束后再被调用,特别是你采用全局的COM对象时更要注意,比如ADO中的连接_ConnetionPtr我就经常声明成全局对象,结果我在OnDestroy里::CoUninitialize();全局智能指针释放时就出错,你要做的就是在::CoUninitialize();把这些对象.Release()。
4、strstream的内存泄漏问题?
strstream在调用str()函数之后如果没有freeze()解冻内存,将会产生内存泄漏,用新版的stringstream就不会有这个问题。