Cherno CPP学习笔记-07-琐碎细节

1.27、唠嗑

P87、C++静态分析

静态分析工具:PVS studio

好像可以在VS中作为一个插件

没什么东西。

P88、C++的参数计算顺序

C++17新特性:后缀表达式必须在别的表达式之前被计算,约定两件事不能同时做。

函数传参,参数连续两个自增,这种行为属于C++未定义行为,具体结果和运算顺序因编译器而定。

P89、C++移动语义 (C++11)

前置知识:左值和右值

移动语义本质上允许我们移动对象(C++11以后引入右值引用),尽可能避免拷贝和分配内存。

移动语义就像是拿一个盒子去扣住一个球,而不是复制一个球再放进盒子里。

#include<iostream>

class String
{
public:
	String() = default;
	String(const char* string)
	{
		printf("Created!\n");
		m_Size = strlen(string);
		m_Data = new char[m_Size];
		memcpy(m_Data, string, m_Size);
	}

	String(const String& other)
	{
		printf("Copied!\n");
		m_Size = other.m_Size;
		m_Data = new char[m_Size];
		memcpy(m_Data, other.m_Data, m_Size);
	}
	//偷来了资源,move含义所在
	String(String&& other)noexcept
	{
		printf("Moved!\n");
		m_Size = other.m_Size;
		m_Data = other.m_Data;

		other.m_Size = 0;
		other.m_Data = nullptr;
	}

	~String()
	{
		printf("Destroyed\n");
		delete m_Data;
	}
	void Print()
	{
		for (uint32_t i = 0; i < m_Size; i++)
			printf("%c", m_Data[i]);
		printf("\n");
	}
private:
	char* m_Data;
	uint32_t m_Size;
};

class Entity
{
public:
	Entity(const String& name)
		: m_Name(name)
	{
	}
	Entity(String&& name)
		: m_Name((String&&)name)
		//: m_Name(std::move(name))
	{
	}
	void PrintName()
	{
		m_Name.Print();
	}
private:
	String m_Name;
};

int main()
{
	Entity entity("Cherno");
	entity.PrintName();
	std::cin.get();
}

P90、std::move与移动赋值操作符

C++三法则:如果需要析构函数,则一定需要拷贝构造函数拷贝赋值操作符

C++五法则:为了支持移动语义,又增加了移动构造函数移动赋值运算符

//P89代码的基础上
String& operator=(String&& other) noexcept
{
    if (this != &other)
    {
        //防止自身已经存储数据造成内存泄漏
        delete m_Data;


        printf("Moved!\n");
        m_Size = other.m_Size;
        m_Data = other.m_Data;

        other.m_Size = 0;
        other.m_Data = nullptr;
    }
    return *this;
}
int main()
{
	//Entity entity("Cherno");
	//entity.PrintName();

	String apple = "apple";
	String dest;
    //String dest = std::move(apple); 这里是移动构造函数

	apple.Print();//apple
	dest.Print();//空

	dest = std::move(apple);  //这里是移动赋值运算符。

	apple.Print();//空
	dest.Print();//apple

	std::cin.get();
}

P91、自己实现Array数组

fixed size and stack allocated array

#include<iostream>

template<typename T, size_t S>
class Array
{
public:
	constexpr size_t Size() const { return S; }

	T& operator[](size_t index) { return m_Data[index]; }
	const T& operator[](size_t index) const { return m_Data[index]; }

	T* Data() { return m_Data; }
	const T* Data() const { return m_Data; }
private:
	T m_Data[S];
};

int main()
{
	Array<int, 5> arr;
	memset(&arr[0], 0, arr.Size() * sizeof(int));
	arr[3] = 4;


	const auto& arrRef = arr;
	for (size_t i = 0; i < arrRef.Size(); i++)
	{
		std::cout << arrRef[i] << std::endl;
	}

	Array<std::string, 2> data;
	data[0] = "Cherno";
	data[1] = "C++";

	for (size_t i = 0; i < data.Size(); i++)
	{
		std::cout << data[i] << std::endl;
	}
	std::cin.get();
}

P92、自己实现Vector数组

搬运别人的笔记:https://www.cnblogs.com/zhangyi1357/p/16009968.html

1.28、开学吧

P93、C++中的迭代器

用法要熟练:

#include<iostream>
#include<vector>
#include<unordered_map>
int main()
{
	std::vector<int> values = { 1,2,3,4,5 };
	for (std::vector<int>::iterator it = values.begin();
		it != values.end(); it++)
	{
		std::cout << *it << std::endl;
	}
	std::unordered_map<std::string, int> map;
	map["Cherno"] = 5;
	map["C++"] = 2;

	for (std::unordered_map<std::string, int>::const_iterator it = map.begin();
		it != map.end(); it++)
	{
		std::cout << it->first << " : " << it->second << std::endl;
	}

	//std::pair<const std::string, int> kv
	for (auto kv : map)
	{
		auto& key = kv.first;
		auto& value = kv.second;
		std::cout << key << " : " << value << std::endl;
	}
    
	//C++17 结构化绑定 P75
	for (auto& [key, value] : map)
	{
		std::cout << key << " : " << value << std::endl;
	}


	std::cin.get();
}

P94、写一个迭代器

(本P没有字幕,依据P92的代码在改)

不如看侯捷STL (摸了

P95、How to REALLY learn C++

省流:做项目&软件广告PS studio

P96、C++中的二进制和按位运算符

讲了一堆二进制(科普级)

P97~P99都没啥用

P100、Maps in C++ (std::map and std::unordered_map)

unordered_map需要重写hash

map 需要重写 < 操作

std::unordered_map中 map[key] 这个操作具有改变(insert)map的能力,故与最好用 map.at(key)

P101、NULL

NULL是一个宏:C++中为0,C中为 ((void *)0)

#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0
    #else
        #define NULL ((void *)0)
    #endif
#endif

nullptr是C++语法,值为0,字节长度与平台有关。

一个关于nullptr类中this的原理例子,什么时候会崩溃。可以取地址,但不能读值。

offsetof宏:可以求类或结构体的中成员的内存偏移

#if defined _MSC_VER && !defined _CRT_USE_BUILTIN_OFFSETOF
    #ifdef __cplusplus
        #define offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
    #else
		//注意这行,s为结构体名,以0为基址求m的内存地址。
        #define offsetof(s,m) ((size_t)&(((s*)0)->m))
    #endif
#else
    #define offsetof(s,m) __builtin_offsetof(s,m)
#endif
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nicer0815

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值