工程常用C++用法

Including .cpp files
thrift 的required、optional探究
gdb 调试利器
【Eigen】从入门到放弃(一):Eigen是个什么鬼?

命令行参数:

GFlags使用文档

#include <gflags/gflags.h>
DEFINE_string(conf_file, "conf/testing.conf", "config file");
gflags::ParseCommandLineFlags(&argc, (char***)&argv, true);
conf::init(FLAGS_conf_file);

捕获异常:

try {
	throw std::runtime_error("input doc error");
} catch (std::exception& ex) {
    LOGF_ERROR("Exception thrown! reason: %s", ex.what());
    return -1;
} catch (...) {
    LOGF_ERROR("Exception thrown! reason unknown");
    return -1;
}

move用法:

C++11右值引用和std::move语句实例解析
std::move()实际应用分析
请勿使用return std::move(obj)返回右值引用

std::make_move_iterator 把*iterator的返回值转换成右值
    std::vector<std::string> v1(s.begin(), s.end()); // copy
    std::vector<std::string> v2(std::make_move_iterator(s.begin()),
                                std::make_move_iterator(s.end())); // move

Move with vector::push_back

#include <vector>
struct A {
    int a;
    int x;
};
int main() {
    using namespace std;
    A a1;
    A a2;
    vector<A> va;
    va.push_back(a1);    //单独使用push back,会完全将a1 copy一份
    va.push_back(move(a2));   //push back+move,会新建变量,但是变量内部的数据来自于a2内部的,使用move后a2就不可用了
}

make share用法:

shared_ptr是一种智能指针(smart pointer),作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。这便是所谓的引用计数(reference counting),比如我们把只能指针赋值给另外一个对象,那么对象多了一个智能指针指向它,所以这个时候引用计数会增加一个,我们可以用shared_ptr.use_count()函数查看这个智能指针的引用计数,一旦最后一个这样的指针被销毁.
Difference in make_shared and normal shared_ptr in C++
智能指针之shared_ptr基本概述
智能指针shared_ptr的reset用法

#include <cpputil/program/conf.h>
extern std::shared_ptr<cpputil::program::Conf> conf;
conf = std::make_shared<cpputil::program::Conf>(filename);


auto servable = std::shared_ptr<Servable>(new EmbeddingServable(FLAGS_model));


int a = new int(100);
std::shared_ptr ptr(a);

std::shared_ptr<int> ptr1 = std::make_shared<int>(15);

std::shared_ptr<int> ptr2(ptr1);
//std::shared_ptr<int> ptr2 = ptr1;这样赋值是错误的,只要是智能指针,这样直接用=赋值是有问题的必须std::shared_ptr<int> ptr2(ptr1);

Difference in make_shared and normal shared_ptr in C++

std::shared_ptr<int> ptr1 = std::make_shared<int>(15);
shared_ptr<string> ss(new string("AAA"));
shared_ptr<string> ss = shared_ptr<string>(new string("AAA"));


shared_ptr<string> ss;
ss.reset(new string("AAA"));

数据格式转换:

#include <boost/lexical_cast.hpp>
boost::lexical_cast<int>(value);
try {
    return boost::lexical_cast<double>(vs);
} catch (boost::bad_lexical_cast) { 
    return default_val;
}

# 字符串拆分
#include <boost/algorithm/string.hpp>
boost::algorithm::split(str_gpus, FLAGS_gpus, boost::algorithm::is_any_of(","));

路径:

::boost::filesystem::path model_root(conf::get_str("model_root"));
::boost::filesystem::path vocab2id_path8(model_root);
vocab2id_path8.append("s1.3.txt", boost::filesystem::path::codecvt());

std::vector<std::pair<std::string, std::string>> pb_path_vec{
        std::make_pair("s1.3", vocab2id_path8.string()),
};

无锁队列:

#include <concurrentqueue/blockingconcurrentqueue.h>
query_queue_ = std::make_shared<moodycamel::BlockingConcurrentQueue<Item>>(10240);

vector 用法:


std::vector<std::thread> threads_seq2seq;
for (int i=0;i<num_threads_seq2seq;++i) {
    threads_seq2seq.emplace_back(std::thread([]{Singleton<Seq2seqServing>::instance().run();}));
}

(1): vector<int> ilist1;

    默认初始化,vector为空, size为0,表明容器中没有元素,而且 capacity 也返回 0,意味着还没有分配内存空间。这种初始化方式适用于元素个数未知,需要在程序中动态添加的情况。

(2): vector<int> ilist2(ilist);

vector<int> ilist2  = ilist; 

两种方式等价 ,ilist2 初始化为ilist 的拷贝,ilist必须与ilist2 类型相同,也就是同为int的vector类型,ilist2将具有和ilist相同的容量和元素

(3): vector<int> ilist = {1,2,3.0,4,5,6,7};

 vector<int> ilist {1,2,3.0,4,5,6,7};

ilist 初始化为列表中元素的拷贝,列表中元素必须与ilist的元素类型相容,本例中必须是与整数类型相容的类型,整形会直接拷贝,其他类型会进行类型转换。

(4): vector<int> ilist3(ilist.begin()+2,ilist.end()-1);

ilist3初始化为两个迭代器指定范围中元素的拷贝,范围中的元素类型必须与ilist3 的元素类型相容,在本例中ilist3被初始化为{3,4,5,6}。注意:由于只要求范围中的元素类型与待初始化的容器的元素类型相容,因此迭代器来自不同的容器是可能的,例如,用一个double的list的范围来初始化ilist3是可行的。另外由于构造函数只是读取范围中的元素进行拷贝,因此使用普通迭代器还是const迭代器来指出范围并没有区别。这种初始化方法特别适合于获取一个序列的子序列。

(5): vector<int> ilist4(7);

默认值初始化,ilist4中将包含7个元素,每个元素进行缺省的值初始化,对于int,也就是被赋值为0,因此ilist4被初始化为包含7个0。当程序运行初期元素大致数量可预知,而元素的值需要动态获取的时候,可采用这种初始化方式。

(6):vector<int> ilist5(7,3);

指定值初始化,ilist5被初始化为包含7个值为3的int
std::vector<GroupBuilder> groups_
groups_.emplace_back(engine, group, vocab);

匿名函数

capture

auto fill_one_field = [](FieldInfo& field_info) { do something }

Lambda 表达式本质上与函数声明非常类似。Lambda 表达式具体形式如下:

[capture](parameters)->return-type{body}
例如:

[](int x, int y){ return x < y ; }
如果没有返回值可以表示为:

[capture](parameters){body}
例如:

[]{ ++global_x; } 
在一个更为复杂的例子中,返回类型可以被明确的指定如下:

[](int x, int y) -> int { int z = x + y; return z + x; }

本例中,一个临时的参数 z 被创建用来存储中间结果。如同一般的函数,z 的值不会保留到下一次该不具名函数再次被调用时。

如果 lambda 函数没有传回值(例如 void),其返回类型可被完全忽略。

在Lambda表达式内可以访问当前作用域的变量,这是Lambda表达式的闭包(Closure)行为。 与JavaScript闭包不同,C++变量传递有传值和传引用的区别。可以通过前面的[]来指定:

[]      // 沒有定义任何变量。使用未定义变量会引发错误。
[x, &y] // x以传值方式传入(默认),y以引用方式传入。
[&]     // 任何被使用到的外部变量都隐式地以引用方式加以引用。
[=]     // 任何被使用到的外部变量都隐式地以传值方式加以引用。
[&, x]  // x显式地以传值方式加以引用。其余变量以引用方式加以引用。
[=, &z] // z显式地以引用方式加以引用。其余变量以传值方式加以引用。
另外有一点需要注意。对于[=]或[&]的形式,lambda 表达式可以直接使用 this 指针。但是,对于[]的形式,如果要使用 this 指针,必须显式传入:

[this]() { this->someFunc(); }();
int x = 4;
auto y = [&r = x, x = x + 1]()->int
    {
        r += 2;
        return x * x;
    }(); // updates ::x to 6 and initializes y to 25.

指针的指针

1,2

int main(int argc, char* const argv[]) {
    gflags::ParseCommandLineFlags(&argc, (char***)&argv, true);
    return run_thrift_server(argc, (char**)argv);
}
class A
{
public:
	A() = default;//正确
	A(int _a) = default;//错误,构造函数需要没有默认参数
	int getA() = default;//错误,仅适用于类的特殊成员函数
}

class A
{
public:
    A();
    A(const A&) = delete;  // 声明拷贝构造函数为 deleted 函数
    A& operator = (const A &) = delete; // 声明拷贝赋值操作符为 deleted 函数
};

线程池:

#include <thread>
tp_ = std::make_shared<ThreadPool>();
tp_->start(static_cast<size_t>(conf::get_int("thread_pool_size", 16)));

omp编程:

OpenMP多线程linux下的使用,简单化
并行计算之OpenMP中的任务调度

#inlcude <omp.h>
#pragma omp parallel for
#pragma omp for reduction(+: 变量)
#pragma omp critical//锁
{
}
#pragma omp parallel for private(x,y)//每个线程都独立拷贝x, y变量,互不干扰,如果不设默认是共享变量
#pragma omp parallel for schedule(static/dynamic/guided, k)//总工作量划分成n/k块,再多线程调度
#pragma omp parallel sections
{
    #pragma omp section//要保证几个section下的函数之间没有变量依赖
    .........
    #pragma omp section
    .........        
}
#pragma omp parallel
{
    .......();
    #pragma omp master/single //保证只有主线程/某个线程能访问下面的函数,区别是使用master没有barrier珊障,single的话先完成的线程等待没完成的线程
    {
    }
    .......
}

#pragma omp barrier/nowait //强制设置珊障/无需等待,如果后续函数对前面的多线程没有依赖,即可使用nowait
#pragma omp parallel for firstprivate(变量)/lastprivate(变量) //为每个多线程赋初值/出多线程回到主线程时赋值供主线程使用

std::function&std::bind&std::future:

聊聊C++异步编程-2
std::function为函数模板类,可以认为是函数的类型声明。
C++ std::function

#include <functional>
std::function<bool(int, int)> fun; //fun变量的类型是输入为int int,输出为bool的函数

std::bind用于包装普通函数,返回std::function类型,bind默认参数为值传递
std::ref和std::cref使用
std::ref 用于包装按引用传递的值。
std::cref 用于包装按const引用传递的值。

#include <functional>
void add_func(int &x, const int &y, int& z) {
    x++;
    y++;
    z++;
}
auto func = std::bind(add_func, std::ref(x), std::cref(y), z);

std::future对象在内部存储一个将来会被赋值的值,并提供了一个访问该值的机制,通过get()成员函数实现。如果有人试图在get()函数可用之前通过它来访问相关的值,那么get()函数将会阻塞,直到该值可用。
c++11多线程编程(八):std::future , std::promise和线程的返回值

std::vector<std::future<int>> rets;
rets = server_->batch_submit();
int ret = rets[i].get();

完整使用:

std::vector<std::function<int()>> task_list;
for (size_t i = 0; i < speeds; i++) {
     task_list.push_back(std::bind(&Index::search, this,    //绑定多个函数
             std::cref(ctx), std::ref(aaa[i])));
}

std::vector<folly::Future<int>> futures;
for (size_t i = 1; i < tasks.size(); ++i) {
	  auto f = folly::via(&executor_, tasks[i]);   //为线程池提交任务
      futures.push_back(std::move(f));
}

if (tasks[0]() != 0) {
     err_cnt += 1;
}

for (auto& f : futures) {
            int ret = std::move(f).get();  //判断并行任务是否完成
}

namespace:

header中使用
Using c++ typedef/using type alias
别再让C++头文件中出现“using namespace xxx;”

using Server = AAA::MultiThreadServer;
namespace whatevs
{
    enum Enum
    {
        FOO = 0,
        BAR,
        BLARGH,
        MEH,
        SIZE
    };
} // namespace whatevs


namespace on = whatevs;
#include "whatevsenum.hpp"
void do_something_with(on::Enum value)
{
    // do stuff
}
do_something_with(on::FOO);

或者 using namespace::whatevs::Enum;
Enum::FOO;

可变(变长)模板:

模板类型可以不定长度
泛化之美–C++11可变模版参数的妙用

#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <vector>
using namespace std;

template <class... T>
void expand(T... args)
{
    vector<type_index> types = {std::type_index(typeid(T))...};  //展开类型
    int arr[] = {(cout<<args<<" ", 0)...};  //展开值
}

template <class... T>
void expandB()
{
    vector<type_index> types = {std::type_index(typeid(T))...};  //展开类型
}

int main() {
    expand<int, int, int, int>(1,2,3,4);  //展开值 cout 1 2 3 4  arr 0 0 0 0
    
    // 可以不用类型
    expand(5,6,7);  //展开值 cout 5 6 7  arr 0 0 0
    
    // 可以不用参数
    expandB<int, int, int>();  //展开值 cout 5 6 7
    return 0;
}

boost::any:

存储任意类型
boost::any 用法

inputs[i] = outputs[idx];  //存入任意类型

std::type_index(typeid(field)) != std::type_index(inputs[idx].type()))  //校验类型

boost::any_cast<decltype(field)>(message_->inputs[idx]);  //转换类型

inserter:

将vector复制到set中

#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_set>

int main()
{
	std::vector<int> input({ 1, 2, 2, 1, 3, 1, 4 });

	std::unordered_set<int> set;
	std::copy(input.begin(),
			input.end(),
			std::inserter(set, set.end()));

	for (const int &i: set) {
		std::cout << i << " ";
	}

	return 0;
}

大量和少量去重对比:

What’s the most efficient way to erase duplicates and sort a vector?

f1: Just using vector, sort + unique
sort( vec.begin(), vec.end() );
vec.erase( unique( vec.begin(), vec.end() ), vec.end() );


f2: Convert to set (using a constructor)
set<int> s( vec.begin(), vec.end() );
vec.assign( s.begin(), s.end() );


f3: Convert to set (manually)
set<int> s;
for (int i : vec)
    s.insert(i);
vec.assign( s.begin(), s.end() );


f4: Convert to unordered_set (using a constructor)
unordered_set<int> s( vec.begin(), vec.end() );
vec.assign( s.begin(), s.end() );
sort( vec.begin(), vec.end() );


f5: Convert to unordered_set (manually)
unordered_set<int> s;
for (int i : vec)
    s.insert(i);
vec.assign( s.begin(), s.end() );
sort( vec.begin(), vec.end() );

前置声明:

如何看待C++前置声明?

随机数:

C++11随机数的正确打开方式
How to shuffle a std::vector?

#include <iostream>
#include <algorithm>
#include <random>
using namespace std;

int main()
{
   std::vector<int> a = {0,1,2,3,4,5,6,7,8,9};
   // 使用rd产生的随机种子,因为种子不确定,rng每次输出不同数值序列,每次shuffle后vector序不一样
   std::random_device rd;
   std::default_random_engine rng(rd());
   // 使用1作为种子,因为种子确定,rng每次输出相同数值序列,每次shuffle后vector序一样
   // std::default_random_engine rng(1);
   std::shuffle(std::begin(a), std::end(a), rng);
   for(int i=0; i<10; i++)
     cout << a[i] << endl;
   return 0;
}

函数后面的const &:

Using ‘const’ in class’s functions
const:说明this指针是一个pointer to const object。如果一个对象为const,它只有权利调用const函数,因为成员变量不能改变。
C++成员函数后加&的作用是什么?
& &&:和const一样,修饰的是*this。其实就是函数重载。

public:
    void foo(int)&;
    void foo(int)&&;
    void foo(int)const;
};

void foo(Test&, int);
void foo(Test&&, int);
void foo(const Test&, int);

json:

rapidjson库的基本使用
Rapidjson的简单使用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值