文章目录
c++11基础知识点
初始化,一切皆可{}初始化,并且可以不加=符号
bash
#include <iostream>
using namespace std;
class Point
{
public:
Point(int x, int y)
: _x(x), _y(y)
{
cout << "构造函数" << endl;
}
~Point()
{
}
private:
int _x;
int _y;
};
int main()
{
int x = 1;
int y = {1};
int z{1};
int a1[] = {1, 2, 3, 4, 5};
int a2[]{1, 2, 3, 4, 5};
Point n1(1, 1);
Point n2 = {1, 1}; //多参数的隐式类型转换 加explicit就不能转换了
Point n3{2, 2};
int *ptr1 = new int[3]{1, 2, 3};
Point *n4 = new Point[2]{{1, 1}, {2, 2}};
return 0;
}
initializer_list容器
c
//c++11中 {10,20,30}这是一个常量数组,被放在常量区
template <class T>
class initializer_list
{
const T* _start;
const T* _finish;
}
//这两个指针分别指向常量区的首部,和最后一个元素的下一个位置。
vector<int> v1 = {1,2,3,4,5} //这后面的列表也是一个initialzer_list,vector的构造函数实现了参数是initalizer_list类型的构造
//vector内部其实是这样实现构造的
vector(initializer_list<value_type> il)
{
reserve(il.size());
for(auto& e:il)
{
push_back(e);
}
}
decltype
c
int i = 1;
auto f = &i;
auto pf = malloc;
cout<<typeid(f).name()<<endl;
cout<<typeid(pf).namej()<<endl;
decltype(pf) pf2;
//typeid推出类型只是一个字符串,只能看不能用
//decltype退出对象的类型,可以定义变量,后者作为模板实参
array
对标的是静态数组,指针解引用,数组越界的情况。
c
int mian()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
array<int,10> aty = {1,2,3,4,5,6};
a[15] = 1; //指针的解引用
aty[15] = 2; //operator[] 函数的调用,内部检查
return 0;
}
forward_list
就是一个单链表,单项迭代器
可变模板参数
原理
c
template<class T>
void ShowList(T value)
{
//结束条件的函数
cout << value << endl;
}
template <class T,class ...Args>
void ShowList(T value, Args... args)
{
cout << value << endl;
ShowList(args...);
}
使用的是编译时递归,而不是采用c语言的方式,并没有把每一个参数都存储起来。
实际用途
c
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
:_month(month)
, _year(year)
, _day(day)
{
}
private:
int _month;
int _year;
int _day;
};
template<class ...Args>
Date* Create(Args... args)
{
Date* ret = new Date(args...);
return ret;
}
int main()
{
Date* A = Create(2001,11,4);
Date* B = Create(A);//甚至传递类也是可以的,调用的是拷贝构造
return 0;
}
emplace
原理:
c
int main()
{
std::list<std::pair<int,string>> mylist;
mylist.emplace_back(10,"soct");//这里底层调用的是构造函数
mylist.emplace_back(make_pair(10,"sock"));//这里底层用的是拷贝构造。
mylist.push_back(make_pair(30,"sort"));//这里是移动构造
mylist.push_back({40,"sort"}); //这里是移动构造
return 0;
}
可以接受参数包用于原地构造对象,也可以接受已经构造好的对象。
参数包:
emplace
系列接口使用了可变参数模板(variadic templates),因此你可以直接传递多个参数来调用对象的构造函数,这允许你直接在容器的内存中构造对象,而不需要先创建临时对象。
已经构造好的对象:
即使你传递的是一个已经构造好的对象,emplace
系列接口仍然会尽可能避免不必要的拷贝或移动操作。具体来说,传递一个对象时,emplace
会利用移动构造函数(如果有),否则会使用拷贝构造函数。
示例:
传递参数包:
cpp
#include <iostream>
#include <vector>
class MyClass {
public:
MyClass(int x, double y) {
std::cout << "Constructor called with x = " << x << ", y = " << y << std::endl;
}
};
int main() {
std::vector<MyClass> vec;
// 使用 emplace_back 传递参数包构造对象
vec.emplace_back(10, 20.5); // 直接调用 MyClass(int, double) 构造函数
return 0;
}
输出:
Constructor called with x = 10, y = 20.5
传递对象:
cpp
#include <iostream>
#include <vector>
class MyClass {
public:
MyClass(int x, double y) {
std::cout << "Constructor called with x = " << x << ", y = " << y << std::endl;
}
MyClass(const MyClass& other) {
std::cout << "Copy constructor called" << std::endl;
}
MyClass(MyClass&& other) noexcept {
std::cout << "Move constructor called" << std::endl;
}
};
int main() {
std::vector<MyClass> vec;
MyClass obj(30, 40.5); // 创建一个对象
// 使用 emplace_back 传递已经构造好的对象
vec.emplace_back(obj); // 这里会调用拷贝构造函数
vec.emplace_back(std::move(obj)); // 这里会调用移动构造函数
return 0;
}
输出:
Constructor called with x = 30, y = 40.5
Copy constructor called
Move constructor called
总结:
- 参数包 :
emplace
系列接口可以传递多个参数,这些参数会被传递给对象的构造函数以在容器中直接构造对象,避免了构造临时对象然后移动或拷贝的开销。 - 传递对象 :如果你传递一个已经构造好的对象,
emplace
会尽量调用移动构造函数(如果对象是通过std::move
传递的),否则调用拷贝构造函数。
emplace
系列接口的优势在于它可以灵活处理不同类型的参数传递方式,从而减少性能损耗,尤其是避免了不必要的拷贝或移动操作。