1)循环引用的案例及解决办法:
#include
#include
using namespace std;
class A;
class B
{
public:
B(){cout<<"B constructor---"<<endl;}
~B(){cout<<"B deconstructor----"<<endl;}
std::weak_ptr<A> pA; //如果是std::shared_ptr,则会造成引用计数永远无法归0,资源不会被释放;
};
class A
{
public:
A(){cout<<"A constructor---------"<<endl;}
~A(){cout<<"A deconstructor----------------"<<endl;}
std::shared_ptr<B> pB;
};
int main()
{
std::shared_ptr<A> pAA = make_shared<A>();
std::shared_ptr<B> pBB = make_shared<B>();
pAA->pB = pBB;
pBB->pA = pAA;
return 0;
}
2)emplace紧调用一次构造函数,push_back调用一次构造,一次拷贝,测试代码如下:
所以:优先使用emplace成员函数。
#include
#include
#include
#include
using namespace std;
struct SBook
{
public:
SBook() : bookName(""), price(0)
{
std::cout << "default construct: " << bookName << std::endl;
}
SBook(std::string bookName_, int price_) : bookName(bookName_), price(price_)
{
std::cout << "construct: " << bookName << std::endl;
};
SBook(const SBook& rhs) : bookName(rhs.bookName), price(rhs.price)
{
std::cout << "copy construct: " << bookName << std::endl;
}
~SBook()
{
std::cout << "deconstruct: " << bookName << std::endl;
}
bool operator <(const SBook& rhs) const
{
return bookName < rhs.bookName;
}
public:
std::string bookName;
int price;
};
int main(int argc, char *argv[])
{
// 测试vector
vector<SBook> books;
// 预先分配,否则整个vector在容量不够的情况下重新分配内存
books.reserve(100);
std::cout << "test push_back:" << endl;
books.push_back(SBook("C++从入门到放弃", 1));
std::cout << endl;
std::cout << "test emplace_back:" << endl;
books.emplace_back("水浒传", 2);
std::cout << endl;
std::cout << "test emplace_back default:" << endl;
books.emplace_back();
auto& book = books.back();
book.bookName = "红楼梦";
book.price = 5;
std::cout << endl;
std::cout << "test emplace:" << endl;
auto it = books.emplace(books.end());
it->bookName = "西游记";
it->price = 3;
std::cout << endl;
std::cout << "output all books: " << endl;
for_each(books.begin(), books.end(), [](const SBook& book)->void
{
std::cout << book.bookName << endl;
});
std::cout << endl;
// 测试set
set<SBook> bookSet;
std::cout << "test bookSet insert:" << endl;
bookSet.insert(SBook("十万个为什么", 1));
std::cout << endl;
std::cout << "test bookSet emplace:" << endl;
bookSet.emplace("新华字典", 2);
std::cout << endl;
std::cout << "output bookset: " << endl;
for_each(bookSet.begin(), bookSet.end(), [](const SBook&book)->void
{
std::cout << book.bookName << endl;
});
std::cout << endl;
return 0 ;
}
3)unordered_map的使用
#include
#include
using namespace std;
template<class K,class V>
using umap = std::unordered_map<K,V>;
int main(void)
{
umap<string,string> m{{"111","bbb"},{"222","ddd"}};
cout<<m["111"]<<endl; //显示key为"111"的value;
return 0;
}
4)利用模板类的参数,自动生成友元函数;
芙蓉楼送辛渐
王昌龄
寒雨连江夜入吴,
平明送客楚山孤。
洛阳亲友如相问,
一片冰心在玉壶;
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。
template<class T1, class T2>
class AA
{
T1 m_x;
T2 m_y;
public:
AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }
// 非模板友元:友元函数不是模板函数,而是利用模板类参数生成的函数,只能在类内实现。
// 本质:编译器利用模板参数,帮我们生成了一个友元函数,但是这个函数不是模板函数
friend void show(const AA<T1, T2>& a)
{
cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}
};
int main(void)
{
AA<int,string> a(44,"abcde");
show(a);
return 0;
}
5)模板类与函数的组合使用(包括:普通函数,函数模板特化版本,函数模板泛化版本)
模板类可以用于函数的参数和返回值!
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。
template<class T1, class T2>
class AA // 模板类AA。
{
public:
T1 m_x;
T2 m_y;
AA(const T1 x, const T2 y) : m_x(x), m_y(y) { }
void show() const { cout << "show() x = " << m_x << ", y = " << m_y << endl; }
};
// 采用普通函数,参数和返回值是模板类AA的实例化版本。
AA<int, string> func(AA<int, string>& aa)
{
aa.show();
cout << "调用了func(AA &aa)普通函数。\n" ;
return aa;
}
// 函数模板,参数和返回值是的模板类AA。
template <typename T1,typename T2>
AA<T1, T2> func(AA<T1, T2>& aa)
{
aa.show();
cout << "调用了func(AA &aa)特化函数。\n" ;
return aa;
}
// 函数模板,参数和返回值是任意类型。
template <typename T>
T func(T &aa)
{
aa.show();
cout << "调用了func(AA &aa)任意类型泛化函数。\n" ;
return aa;
}
int main()
{
AA<int, string> aa1(3, "我是一只傻傻鸟。"); //以上三个函数,优先调用普通函数,再次调用特化版本,最后是泛化版本!
func(aa1);
AA<double,string> aa2(3.4,"5555"); //特化版本
func(aa2);
}
6)模板类继承普通类范例:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class aa
{
public:
int a_;
aa(int a) :a_(a) { cout << "调用了AA的构造函数。\n"; }
void func1() { cout << "调用了func1()函数:m_a=" << a_ << endl;; }
};
template<class T1,class T2>
class bb : public aa
{
public:
T1 x_;
T2 y_;
bb(T1 x,T2 y,int a): aa(a),x_(x),y_(y){ cout << "调用了BB的构造函数"<<endl;}
void func2() const { cout << "调用了func2()函数:x = " << x_ << ", y = " << y_ << endl; }
};
int main(void)
{
bb<int, string> bb(8, "我是一只傻傻鸟。",3);
bb.func2();
bb.func1();
return 0;
}
学习知识tips:
引用是指针常量的伪装
构造函数一般有两个执行阶段:初始化阶段和赋值阶段;
成员指针运算符 .* 或者 ->* c++特有的
std::is_same //类型萃取相关的函数
integral 美 [ˈɪntɪɡrəl] adj 完整的,n积分
typeid跟sizeof用法意义,有两种写法 typeid(int);
typeid(变量名或者表达式);
7)匿名共用体一般是写在结构体中的
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。
struct st_girl // 定义超女结构体。
{
int no; // 超女编号。
union // 定义匿名共同体udata。
{
int a;
double b;
char c[21];
};
};
int main()
{
st_girl girl;
cout<<sizeof(girl)<<endl;
//输出是32 = 4 + 4 + 24; 空的union占1个字节;那为什么4个呢,因为得字节对齐
return 0;
}
8)共用体使用方法:
#include // 包含头文件。
using namespace std; // 指定缺省的命名空间。
union udata // 定义共同体udata。
{
int a;
double b;
char c[21];
};
int main()
{
udata data;
cout << "sizeof(data)="<< sizeof(data) << endl;
cout << "data.a的地址是:" << (void*) & data.a << endl; //输出地址相同
cout << "data.b的地址是:" << (void*) & data.b << endl;//输出地址相同
cout << "data.c的地址是:" << (void*) & data.c << endl;//输出地址相同
data.b = 30;
cout << "data.a=" << data.a << endl;
cout << "data.b=" << data.b << endl;
cout << "data.c=" << data.c << endl;
}
输出结果:
sizeof(data)=24
data.a的地址是:0x7ffd02aa4860
data.b的地址是:0x7ffd02aa4860
data.c的地址是:0x7ffd02aa4860
data.a=0
data.b=30
data.c=