C++ 进阶汇总 [持续更新-建议收藏]

进阶目录


1.lambda表达式

#include <functional>
#include <iostream>

int main(){
std::function<void(void)> fun = [](){
        int a = 1;
        std::cout << a << std::endl;
};
fun();
}

2.using 类内函数指针重命名 [相同类型不同函数,放置到 std::map 中会有用,减少代码量]

#include <iostream>

class c{
public:
        using pfunc_type = void(c::*)();
        pfunc_type pfunc = nullptr;
        c(){ pfunc = &c::up;}
        inline void call(){ (this->*pfunc)(); }
private:
        int num                  = 0;
        void up(){
                ++num;
                std::cout << num << std::endl;
        }
};

int main(){
        c  *C = new c;
        C->call();
        delete C;
}

3.指针引用

#include <iostream>
int main(){
        int a = 3;
        
        /* 指针引用 */
        int * const &p = &a;
        *p = 4;
        std::cout << a << std::endl;
        
        /* 原始引用 */
        int &theA = *p;
        theA = 5;
        std::cout << a << std::endl;
}

4.tuple使用

#include <iostream>
#include <tuple>
#include <functional>
#include <string>

int main() {

        /* 声明时赋值 */
        std::tuple<std::string, std::function<void()>> tp("i++", [](){
                static int i = 0;
                std::cout << i++ << std::endl;
        } );

        std::cout << "call " << std::get<0>(tp) << std::endl;
        std::get<1>(tp)();
        /* 先声明,后赋值 */
        std::tuple<float, std::string> id2name;
        id2name = make_tuple(1.5, std::string("gulou"));
        std::cout << "id :" << std::get<0>(id2name) << " name :" << std::get<1>(id2name) << std::endl;
}

5.读取文件到字符串 [遇到 空格/回车 结束]

#include <iostream>
#include <fstream>
#include <string>

inline std::string readUrl( std::string fName="input.txt", std::string result="" ) { std::ifstream os; return os.open(fName), os >> result, os.close(), result; }

int main()
{
        std::cout << readUrl();
}

6.call_once 控制调用一次

#include <iostream>
#include <mutex>

/* compile : g++ call_once.cpp -std=c++11 -pthread */
int main(){
    std::once_flag flag; /* 如果你的函数操作不会产生异常,那么可以使用std::call_once,使得代码更加的安全简洁易读。 */
    unsigned int MAX = 50;

    std::call_once(flag, [&MAX ]() { MAX = (MAX == 50) ? (MAX + 2950) : MAX ; } );
    std::call_once(flag, [&MAX ]() { MAX = (MAX == 50) ? (MAX + 2950) : MAX ; } );

    std::cout << MAX << std::endl; /* output :3000 */
}

7.algorithm 之 find_if 、swap

#include <iostream>     /* std::cout */
#include <algorithm>    /* std::find_if */
#include <vector>       /* std::vector */

/* compile : g++ find_if.cpp -std=c++11 */
int main () {
	std::vector<int> vec_i;
	
	vec_i.push_back(10);
	vec_i.push_back(55);
	vec_i.push_back(25);
	
	/*      Returns an iterator to the first element in the range [first,last) for which pred returns true.
	        If no such element is found, the function returns last. */
	auto it = std::find_if (vec_i.begin(), vec_i.end(), [](int &i) { return (i%2) == 1; });
	if ( it != vec_i.end() ) {
	        std::cout << "The first odd value is " << *it << std::endl;
	}
	
	std::swap(vec_i[1], vec_i[2]); /* Exchanges the values of a and b. parameters all reference, impl by std::move */
	
	it = std::find_if (vec_i.begin(), vec_i.end(), [](int &i) { return (i%2) == 1; });
	if ( it != vec_i.end() ) {
	        std::cout << "The first odd value is " << *it << std::endl;
	}
	return 0;
}


8.unique_ptr 示例

    std::unique_ptr<AVFrame, void(*)(AVFrame*) > unique_p(av_frame_alloc(), [](AVFrame *ptr){
        av_frame_free(&ptr);
    });

9.运行时计算 【constexpr 】

#include <iostream>
#include <string>

enum class languageType:int {
    CH,
    EN,
    JAP,
};

static languageType lan = languageType::EN;

constexpr const char* languageName ( const languageType lan) {
        return languageType::CH == lan ? "中文": \
               languageType::EN == lan ? "English" : \
               /*     JAP     */         "日本語";
}

int main(){
  std::cout << languageName (lan) << std::endl;
  return 0;
}
---

10.字符串格式化 【string format 】

std::string StringFormat(const char* fmt, ...) {

	char buffer[kMaxSize];
	
	va_list args;
	va_start(args, fmt);
	int result = vsnprintf(buffer, kMaxSize, fmt, args);
	va_end(args);
	
	if ( result < 0) { /* error */
	      std::cout << "String Format Convert Error : " << kMaxSize << " " << result << std::endl;
	} else if ( result > kMaxSize ) { /* warning */
	      std::cout << "String Format Convert Warning : truncated string" << std::endl;
	}
	
	return std::string(buffer);
}
/* usage:
	std::cout << StringFormat("hello %s","world!") << std::endl;
*/

11.字符串查找最后一个对应字符后的字符串

#include<bits/stdc++.h>

int main(){
        std::string s(R"(https://editor.csdn.net/md/?articleId=126165427)");
        int ret = s.find_last_of('/');
        if (ret != std::string::npos) {
                s = s.substr(ret+1, 999);;
                std::cout << s << std::endl;
        } else {
                std::cout << "error" << std::endl;
        }
}
/*  result:
[root@jn string]# ./a.out
?articleId=126165427
[root@jn string]#*/

12.基于C++11的毫秒计时器类,精度到0.001ms,开箱即用

#include <iostream>
#include <chrono>
#include <thread>

class jnTimer {
public: /* return milliseconds escaped, Precision to 0.001 ms*/
    jnTimer(){ update(); }
    inline void update() { begin = HrClock::now(); }
    inline double diff() { return std::chrono::duration_cast<MicroSeconds>(HrClock::now() - begin).count() / 1e3; }

private:
    using HrClock      = std::chrono::high_resolution_clock;
    using MicroSeconds = std::chrono::microseconds;

    HrClock::time_point  begin{ MicroSeconds::zero() };
};

/* compile: g++ -std=c++11 timer.cpp */
int main()
{
        jnTimer timer; /* timer.update(); */
        std::this_thread::sleep_for( std::chrono::milliseconds( 300 ) );/* do your work */
        std::cout << "diff:" << timer.diff() << std::endl;

        return 0;
}

13.三分钟读完《Essential C++》

https://blog.csdn.net/weixin_44328568/article/details/131720185


14.计算字节为对应单位的大小[human-readable]

#include <stdint.h>
#include <cstdlib>
#include <cstdio>
std::string bytesToSize(uint64_t bytes)
{
    static const char* suffixes[] = {"B", "KB", "MB", "GB", "TB"};
    int i = 0;
    double dblBytes = bytes;
    while (dblBytes >= 1024 && i < sizeof(suffixes) / sizeof(suffixes[0]) - 1) {
        dblBytes /= 1024;
        i++;
    }
    char buffer[32];
    snprintf(buffer, sizeof(buffer), "%.2f %s", dblBytes, suffixes[i]);
    return std::string(buffer);
}

15.enum与字符串在固定(不修改)数据上的关联操作[代替std::map会更高效]

#include <iostream>
#include <string>

enum Fruit {
    APPLE,
    BANANA,
    CHERRY,
    COUNT /* COUNT 用于获取 enum 的项数,始终放在最后 */
};

const std::string FruitNames[COUNT] = {
    "Apple",
    "Banana",
    "Cherry"
};

int main() {
    Fruit fruit = BANANA;

    std::cout << "Selected fruit: " << FruitNames[fruit] << std::endl;

    return 0;
}

16.C++奇异递归模板模式

https://blog.csdn.net/weixin_44328568/article/details/132913145?spm=1001.2014.3001.5501

17.加载文件到std::vector<uint8_t>

bool loadDataToVec( const char * FileName, std::vector<uint8_t> &dataVec){

    std::ifstream file( FileName, std::ios::binary);
    if (!file) {
	std::cerr << "open file error" << std::endl;
        return false;
    }

    file.seekg(0, std::ios::end); // 移动到文件末尾
    std::streamsize size = file.tellg(); // 获取当前位置(即文件大小)
    file.seekg(0, std::ios::beg); // 重置到文件开始

    std::vector<uint8_t> data(size);

    if (!file.read(reinterpret_cast<char*>(data.data()), size)) {
	std::cerr << "read file error" << std::endl;
        return false;
    }

    file.close();

    dataVec = std::move(data);

    return true;
}

18.为什么不建议 用offsetof

  • 不适用于非标准布局的结构体:** offsetof仅在标准布局的结构体中有效。如果结构体包含虚拟函数、继承等非标准布局特性,offsetof的行为将变得不确定。
  • 不适用于空结构体:** 对于空结构体,offsetof无法正确计算成员的偏移量,因为空结构体的大小为0,成员的偏移量也无法确定。
  • 可读性差:** 使用offsetof来计算成员的偏移量会使代码变得复杂和难以理解,尤其是对于不熟悉offsetof的开发者来说。
  • 可移植性差:** 虽然offsetof是C/C++标准库中的宏,但并不是所有平台和编译器都对其实现完全一致,可能会存在一些细微的差异,降低了代码的可移植性。

19.thread_local:各线程独立实例

C++11 引入的关键字,用于声明线程局部存储(Thread Local Storage, TLS)。它确保每个线程都有独立的实例,这样在多线程环境下,线程之间不会干扰对方的变量,从而避免竞争条件和数据一致性问题。

  • 用法
①声明和初始化

使用 thread_local 声明的变量在每个线程中都有独立的实例。这些变量在线程首次访问时初始化,并在线程退出时销毁。

thread_local int var = 0;

上面的声明表示每个线程都有一个名为 var 的整数变量,初始值为 0。每个线程对 var 的修改不会影响其他线程的 var

②作用域

thread_local 可以用于全局变量、静态变量和局部变量。以下是几种不同的用法:

  1. 全局变量

    thread_local int globalVar = 1;
    
  2. 类静态成员变量

    class MyClass {
    public:
        static thread_local int threadLocalVar;
    };
    
    thread_local int MyClass::threadLocalVar = 2;
    
  3. 函数内局部变量

    void function() {
        thread_local int localVar = 3;
    }
    
③示例:线程局部存储

多线程环境下使用 thread_local 确保每个线程都有独立的变量实例:

#include <iostream>
#include <thread>
#include <chrono>

// 声明线程局部变量
thread_local int threadVar = 0;

void threadFunction(int id) {
    // 每个线程独立地修改 threadVar
    threadVar = id;
	std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Thread " << id << " has threadVar = " << threadVar << std::endl;
}

int main() {
    std::thread t1(threadFunction, 1);
    std::thread t2(threadFunction, 2);

    t1.join();
    t2.join();

    return 0;
}

推荐文章

C++11 玩家不得不学的语法集 [持续更新-建议收藏]

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值