栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c++总结(2)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++总结(2)

1、initializer_list
auto i = {1, 2, 3, 4};
cout << typeid(i).name()<

c++11中的vector vec{1,2,3};就是使用了initializer_list,可变参数也是使用的initializer_list。initializer_list最常用的方式是通过大括号包围的值列表对其进行初始化:除了不能修改vlist中的值以外,可以像一般的list一样使用。

vector和initializer_list的区别

  • vector有push_back操作,其有reserve重新new内存空间,是在堆中进行的操作,而initializer_list是在栈上,其内部只有begin和end函数,函数内不能修改这些数值
  • vector会发生拷贝,而initializer_list是指针语义,里面的元素不会被拷贝
2、map
  •  map没有赋值的时候是被初始化为0的
	std::map m;
	int a = m[1110];
    
    //输出 a为0
  •  map自定义键值类型

map底层的实现是红黑树,红黑树具有二叉搜索树的性质,map在插入的时候具有对key进行排序的功能,这是因为c++的基本类型有默认的比较方式,即便是string类型,其可以自动排序那是因为string内部实现了operator < 的重载。

        类或结构体中重载operator<

#include 
#include 
#include 
using namespace std;

class Person {
public:
	string name;
	int age;

	Person(string n, int a) 
	{
		name = n;
		age = a;
	}

    //重载operator<
	bool operator<(const Person &p) const //注意这里的两个const
	{
		return (age < p.age) || (age == p.age && name.length() < p.name.length());
	}
};

int main() 
{
	map group;
	group[Person("David", 27)] = 2;
	group[Person("Eric", 18)] = 3;
	for (auto iter = group.begin(); iter != group.end(); iter++)
	{
		cout << iter->first.name
			<< " " << iter->first.age
			<< " : " << iter->second
			<< endl;
	}

	return 0;
}
3、为什么析构函数是虚函数

当基类的指针指向派生类的时候要将基类的析构函数设置为虚函数,这样是为了防止派生类无法析构导致内存泄露

  • 基类析构未使用虚函数
#include
using namespace std;
class base {
public:
	base() {};
	~base() { cout << "Output from the destructor of class base!" << endl; };

	void DoSomething() { cout << "Do something in class base!" << endl; };
};

class Derived : public base {
public:
	Derived() {};
	~Derived() { cout << "Output from the destructor of class Derived!" << endl; };

	void DoSomething() { cout << "Do something in class Derived!" << endl; }
};
int main() 
{
	base *p = new Derived;
	p->DoSomething();
	delete p;
	return 0;
}

上述代码,未使用virtual,输出的结果没有进入派生类的析构函数中,会导致内存泄露的发生。

  •  基类析构函数使用虚函数
#include
using namespace std;
class base {
public:
	base() {};
	virtual ~base() { cout << "Output from the destructor of class base!" << endl; };

	void DoSomething() { cout << "Do something in class base!" << endl; };
};

class Derived : public base {
public:
	Derived() {};
	~Derived() { cout << "Output from the destructor of class Derived!" << endl; };

	void DoSomething() { cout << "Do something in class Derived!" << endl; }
};
int main() 
{
	base *p = new Derived;
	p->DoSomething();
	delete p;
	return 0;
}

根据多态的性质,在释放的时候就是先析构派生类,然后在析构基类

4、static介绍
  1. 静态资源是类初始化的时候加载的,
  2. 而非静态资源是类实例化对象的时候加载的,
  3. 类的初始化早于类实例化对象 
  •  静态成员函数属于整个类,在类实例化之前就已经分配空间了。而非静态成员必须在类实例化之后才能有内存空间。
#include 
using namespace std;
class Point
{
public:
	void init()
	{
	}
	static void output()
	{
        //error  报非静态成员引用必须与特定对象对应,即静态成员函数不能调用非静态变量
		cout << m_x << endl;    
	}

	static void output1()
	{
        //ok  没有非静态成员就可以
		cout << “hello”<< endl;    
	}
private:
	int m_x;
};
void main()
{
	Point pt;
	pt.output();
}
  • 非静态成员函数可以调用静态变量,前提是静态变量要提前在类外初始化
#include 
class Point
{
public:
	Point()
	{
		m_nPointCount++;
	}
	~Point()
	{
		m_nPointCount--;
	}
	static void output()
	{
		printf("%dn", m_nPointCount);
	}
private:
	static int m_nPointCount;
	int m_1;
};
int Point::m_nPointCount = 0;    //初始化则ok,否则不ok
void main()
{
	Point pt;
	pt.output();
}
5、私有构造函数
  • 将构造函数私有化之后就不能在类的外部构造对象了,也不能在外部构造子类的对象了。但是可以通过一个public的static静态函数来访问类中定义的函数和静态成员,单例模式就是这样。
  • 这样的好处就是可以阻止用户在类外调用析构该对象了。
#include
using namespace std;

class Singleton
{
private:
	Singleton()
	{
		cout << "Singleton" << endl;
	}

public:
	static Singleton* getInstance()
	{
		if (m_instance == nullptr)
			m_instance = new Singleton;
		return m_instance;
	}

    //析构函数中释放,delete是不对的,析构函数中的delete会再次进入析构,导致循环调用了
	~Singleton()
	{
		//if (m_instance)
		//{
		//	cout << "~Singleton" << endl;
		//	delete m_instance;
		//	m_instance = nullptr;		
		//}
	}
        
    //释放
	void Release()
	{
		if (m_instance)
		{
			cout << "~Singleton" << endl;
			delete m_instance;
			m_instance = nullptr;
		}
	}
private:
	static Singleton *m_instance;
};

Singleton *Singleton::m_instance = nullptr;

int main()
{
	Singleton* m1 = Singleton::getInstance();
	Singleton* m2 = Singleton::getInstance();
	m1->Release();

    //error
    //delete m1;
    //m1 = nullptr;
}

也可以通过在类内部定义一个静态成员变量来释放单例的内存,静态成员变量会在程序结束的时候自动进入析构释放资源。 所以该静态成员变量是需要是一个实现析构的类。

程序在结束的时候,系统会自动析构所有的全局变量和所有的类的静态成员变量。利用这个特征,我们可以在单例类中定义一个静态成员变量,而它的唯一工作就是在析构函数中删除单例类的实例。

#include
using namespace std;

class Singleton
{
private:
	Singleton()
	{
		cout << "Singleton" << endl;
	}

public:
	static Singleton* getInstance()
	{
		if (m_instance == nullptr)
			m_instance = new Singleton;
		return m_instance;
	}

	~Singleton()
	{
		//if (m_instance)
		//{
		//	cout << "~Singleton" << endl;
		//	delete m_instance;
		//	m_instance = nullptr;		
		//}
	}

	void Release()
	{
		if (m_instance)
		{
			cout << "~Singleton" << endl;
			delete m_instance;
			m_instance = nullptr;
		}
	}

	
	class CRelease
	{
	public:
		~CRelease()
		{
			if (m_instance)
			{
				cout << "~Singleton" << endl;
				delete m_instance;
				m_instance = nullptr;
			}
		}
	private:
		static CRelease m_re;
	};
private:
	static Singleton *m_instance;
	
};

Singleton *Singleton::m_instance = nullptr;
Singleton::CRelease mRelease;	//静态变量需要初始化,要不然进不去析构函数
int main()
{
	Singleton* m1 = Singleton::getInstance();
	Singleton* m2 = Singleton::getInstance();
	//m1->Release();
}

 shared_ptr并自定义deleter

#include 
#include 
using namespace std;

mutex mtx;

class Singleton
{
public:
	static shared_ptr getInstance()
	{
		//双重检查,避免单重检查每次都加锁
		if (m_instance == nullptr)
		{
			lock_guard lck(mtx);
			if(m_instance == nullptr)
				m_instance = make_shared();
		}
			
		return m_instance;
	}
private:
	static void Release(Singleton *s)
	{
		cout << "Release" << endl;
		delete s;
	}

private:
	static shared_ptr m_instance;
};

shared_ptr Singleton::m_instance(nullptr, Singleton::Release);

int main()
{
	shared_ptr m1 = Singleton::getInstance();
	shared_ptr m2 = Singleton::getInstance();
}
6、thread的拷贝、转移问题

c++11中的thread不能被拷贝,其内部没有拷贝构造函数,thread的源码如下:

    thread(thread&& _Other) noexcept
		: _Thr(_Other._Thr)
		{	// move from _Other
		_Thr_set_null(_Other._Thr);
		}

	thread& operator=(thread&& _Other) noexcept
		{	// move from _Other
		return (_Move_thread(_Other));
		}

	thread(const thread&) = delete;
	thread& operator=(const thread&) = delete;

将thread传递的时候要使用右值引用和move函数

#include 
#include 

using namespace std;

class CThread
{
public:
	CThread(thread &th):m_th(move(th))
	{
		cout << "nCThread, id:" << m_th.get_id() << 
			", joinable status is:" << m_th.joinable() << endl;
	}

	~CThread()
	{
		cout << "~CThread" << endl;
		m_th.join();
	}

	CThread(const CThread &th) = delete;
	CThread &operator=(const CThread &th) = delete;

private:
	thread m_th;
};

void func()
{
	cout << "func" << endl;
}
int main()
{
	thread t(func);
	cout << "thread before move, id:" < 
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/457168.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号