c++ summary

2020-11-01

Ref:

C++ 49 question

C++ 59 question

C++ 79

C++ 30

C++ 常问题

  1. struct alignment save read data cycle from memory data reading. 按结构体中size最大的成员对齐.
  2. Reference(alter name) & pointer(variable): reference is not dorminate space. Reference only once. Pointer could be empty.
  3. stack vs heap: stack(system, to lower address); heap(high address, by self)
  4. *p[10]: pointer array; ( *p)[10]: array pointer; function pointer -> int ( *p)(int)
  5. Virtual function table static like. In compilier time, create VFT. Running time polymorphysm.
  6. new/delete vs malloc/free: malloc是大小需要自己算的。delete会调用
  7. macro: compile; typedef: 检查类型。
  8. const int *: 内容不变;int * const p: 指针本身不能改变。
  9. dangling pointer: free/delete之后没有设置为nullptr; 野指针就是wild pointer. Smart pointer is to avoid for the dangling pointer.
  10. Compiling process: define is in pre-processing.
  11. static: class static all seen; static member funcion: no this, can not use non-static function. static init is before main.
  12. const member: 构造函数的时候可以赋值。const成员函数:const对象不可以调用非const成员函数
  13. override: 基类必须有这个。 final: 不希望某个类或者某个虚函数的继承。
  14. template: template specification template<>.
  15. why destructor is virtual function? If not dynamic binding, can not destruct the child class memory.
  16. dynamic_cast, static_cast, const_cast.
  17. overload: same function name, different input parameter type or number of param. not return type.
  18. hide: A a; B b; b.A::fun(2).
  19. How to implement polymophysim? virtual.如果对象类型是派生类,就调用派生类的函数,如果对象类型是基类,就调用基类的函数。virtual虚函数的标志。
  20. inline:有循环的话,开销会比较大。
  21. auto:compling with init value;decltype:decltype(a) b. decltype(auto)
  22. private, protected, public:
  23. Big end vs little end: big end -> 字数据的高字节存储在低地址中
  24. volatile: 系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。explicit是防止隐式转换。
  25. When to call copy contructor?

Advanced C++ question.

STL

  1. vector: 连续内存,如果需要插入和删除操作,需要内存块拷贝。可以实现动态增长,在尾部插入更高效一些。使用swap可以来清空vector的内存空间。array是底层。
  2. list:双向链表。 forward list:单向的;类似于stack。
  3. map、set、multiset、multimap:red black tree。insert的方法:insert piar,insert value type,insert make_pair, use array like. red black tree的特性:每个节点都是红色或者黑色;根节点为黑色;如果节点为红色,子节点一定是黑色。任意节点从树尾端的任何路径,所包含的黑色节点数量一定相同。
  4. Unordered_map,unordered_set、unordered_multiset、unord_multimap:使用hash table。
  5. stack、queue:都是适配器。使用list,deque,vector实现。
  6. priority_queue: 最大堆,是适配器。底层使用vector或者是deque。

C++ modern feature

  • Bit field: uint32_t var : 8;

  • Static_assert: print error at the compiling time.
  • Abseil
  • class member with constexpr must be static.
  • const class member only could be initialized in the constructor.
  • Optional: return null opt is not exists.

Implementation of smart pointer

  • Why smart pointer? Bare(raw) pointer can not know its objects is single object or array. Can not know its ownership. The destructor is evil and easier to be wrong. Not sure the pointer is dangle or not.
  • Smart pointer: unique_ptr, shared_ptr, auto_ptr, weak_ptr. auto_ptr is the C++98 unique_ptr version. But not good as unique_ptr.
  • unique_ptr: could be only used in the move with dominate ownership. unique_ptr could be transformed into shared_ptr.
  • shared_ptr: objects memory shared. One counter for the shared_ptr, count +1 for the reference, -1 for the destructor. size of shared_ptr is double of bare pointer. One pointer for the bare pointer. counter is the atomic operation.(make sure only one thread is visiting)Move will not add the counter. Do not use bare pointer for the shared_ptr init, using unique_ptr, shared_ptr, auto_ptr. No such std::shared_ptr<T[]> for the array, but there is for the unique_ptr like: std::unique_ptr<T[]>.
  • weak_ptr is constructed by the shared_ptr. weak_ptr not affected the counter. Using weak_ptr to test the dangle or expired situation. Using atomic operation to do this. Using weak_ptr::lock. Shared_ptr ref each other, should be fixed by the weak_ptr. Weak_ptr as cache.
  • unique_ptr implementation:
// https://www.jianshu.com/p/77c2988be336
template<typename T>
class MyUniquePtr
{
public:
   explicit MyUniquePtr(T* ptr = nullptr)
        :mPtr(ptr)
    {}

    ~MyUniquePtr()
    {
        if(mPtr)
            delete mPtr;
    }

    MyUniquePtr(MyUniquePtr &&p) noexcept;
    MyUniquePtr& operator=(MyUniquePtr &&p) noexcept;

    MyUniquePtr(const MyUniquePtr &p) = delete;
    MyUniquePtr& operator=(const MyUniquePtr &p) = delete;

    T* operator*() const noexcept {return mPtr;}
    T& operator->()const noexcept {return *mPtr;}
    explicit operator bool() const noexcept{return mPtr;}

    void reset(T* q = nullptr) noexcept
    {
        if(q != mPtr){
            if(mPtr)
                delete mPtr;
            mPtr = q;
        }
    }

    T* release() noexcept
    {
        T* res = mPtr;
        mPtr = nullptr;
        return res;
    }
    T* get() const noexcept {return mPtr;}
    void swap(MyUniquePtr &p) noexcept
    {
        using std::swap;
        swap(mPtr, p.mPtr);
    }
private:
    T* mPtr;
};

template<typename T>
MyUniquePtr<T>& MyUniquePtr<T>::operator=(MyUniquePtr &&p) noexcept
{
    swap(*this, p);
    return *this;
}

template<typename T>
MyUniquePtr<T> :: MyUniquePtr(MyUniquePtr &&p) noexcept : mPtr(p.mPtr)
{
    p.mPtr == NULL;
}
  • shared_ptr implementation:
// https://cloud.tencent.com/developer/article/1688444
#include<iostream>
#include<mutex>
#include<thread>
using namespace std;

template<class T>
class Shared_Ptr{
public:
	Shared_Ptr(T* ptr = nullptr)
		:_pPtr(ptr)
		, _pRefCount(new int(1))
		, _pMutex(new mutex)
	{}
	~Shared_Ptr()
	{
		Release();
	}
	Shared_Ptr(const Shared_Ptr<T>& sp)
		:_pPtr(sp._pPtr)
		, _pRefCount(sp._pRefCount)
		, _pMutex(sp._pMutex)
	{
		AddRefCount();
	}
	Shared_Ptr<T>& operator=(const Shared_Ptr<T>& sp)
	{
		//if (this != &sp)
		if (_pPtr != sp._pPtr)
		{
			// 释放管理的旧资源
			Release();
			// 共享管理新对象的资源,并增加引用计数
			_pPtr = sp._pPtr;
			_pRefCount = sp._pRefCount;
			_pMutex = sp._pMutex;
			AddRefCount();
		}
		return *this;
	}
	T& operator*(){
		return *_pPtr;
	}
	T* operator->(){
		return _pPtr;
	}
	int UseCount() { return *_pRefCount; }
	T* Get() { return _pPtr; }
	void AddRefCount()
	{
		_pMutex->lock();
		++(*_pRefCount);
		_pMutex->unlock();
	}
private:
	void Release()
	{
		bool deleteflag = false;
		_pMutex->lock();
		if (--(*_pRefCount) == 0)
		{
			delete _pRefCount;
			delete _pPtr;
			deleteflag = true;
		}
		_pMutex->unlock();
		if (deleteflag == true)
			delete _pMutex;
	}
private:
	int *_pRefCount;
	T* _pPtr;
	mutex* _pMutex;
};

Lock Study

  • https://tech.meituan.com/2018/11/15/java-lock.html

Move and Forward

  • Move: move the unique_ptr, future, thread.
  • Forward: receive any real parameter function template.

  • right value reference make move and forward become possible.