c++11 你需要知道这些就够了

https://blog.csdn.net/tangliguantou/article/details/50549751

c++11新特性


举着火把寻找电灯

enter description here


今天我就权当抛砖引玉,如有不解大家一起探讨。有部分内容是引用自互联网上的内容,如有问题请联系我。


T&& 右值引用 std::move

右值引用出现之前我们只能用const引用来关联临时对象(右值)所以我们不能修临时对象的内容,右值引用的出现就让我们可以取得临时对象的控制权,终于可以修改临时对象了!

int main()
{int i = 42;int &r = i; // ok: r refers to iint &&rr = i;   // error: cannot bind an rvalue reference to an lvalueint &r2 = i * 42;   // error: i * 42 is an rvalueconst int &r3 = i * 42; // ok: we can bind a reference to  const  to an rvalueint &&rr2 = i * 42; int &&rr3 = rr2;   // error: the expression rr2 is an lvalue!return 0;
}

即凡是可以 vartype varname; 这样定义出来的变量(variable)其自身都是左值。

std::move相关。 右值引用因为绑定对象即将被销毁,意味着没有人会继续访问他们,所以就可以把他们(的资源)steal(偷)过来。 虽然不能将右值引用绑在左值上,但通过利用utility头文件新增的函数模板move,它返回传入对象的右值引用,可以达到 steal的效果。

int &&rr3 = std::move(rr2); // ok

再提醒:一旦使用了move,编译器就默认传入对象已经不打算使用了,是可以被销毁的,move之后该对象的值已经不确定,不要再访问。还有由于对象偷取与复制的差别巨大,不注意会产生非常难定位的bug,所以所有使用move的地方一定要使用全称std::move,给大家以提醒。(其实c++11在algorithm头文件也新增了一个move,参数与意义都与此截然不同)。

#include <iostream>
using namespace std;class HugeMem{public:HugeMem(int size): sz(size > 0 ? size : 1) {c = new int[sz];}~HugeMem() { cout<<"HugeMem 析构\n";delete [] c; }HugeMem(HugeMem && hm): sz(hm.sz), c(hm.c) {cout<<"HugeMem move 构造\n";hm.c = nullptr;}int * c;int sz;
};
class Moveable{public:Moveable():i(new int(3)), h(1024) {}~Moveable() { cout<<"Moveable 析构\n";delete i; }Moveable(Moveable && m):i(m.i), h(move(m.h)) {      // 强制转为右值,以调用移动构造函数m.i = nullptr;}int* i;HugeMem h;
};Moveable GetTemp() {//Moveable tmp = Moveable();Moveable tmp;cout << hex << "Huge Mem from " << __func__<< " @" << tmp.h.c << endl; // Huge Mem from GetTemp @0x603030return tmp;
}int main() {Moveable a(GetTemp());cout << hex << "Huge Mem from " << __func__<< " @" << a.h.c << endl;   // Huge Mem from main @0x603030
}

早在C++11之前编译器就把优化几乎做到了极致——局部变量返回到函数外部并赋值给外部变量这个过程基本上不存在任何多余的临时变量构造和析构,这比move机制更加高效。显式指定move以后,return std::move(localvar)这里会强行从localvar移动构造一个临时变量temp,然后return temp(temp这里会有RVO优化)。

auto for循环

需要注意的是,auto不能用来声明函数的返回值。但如果函数有一个尾随的返回类型时,auto是可以出现在函数声明中返回值位置。这种情况下,auto并不是告诉编译器去推断返回类型,而是指引编译器去函数的末端寻找返回值类型。在下面这个例子中,函数的返回值类型就是operator+操作符作用在T1、T2类型变量上的返回值类型。

template <typename T1, typename T2>
auto compose(T1 t1, T2 t2) -> **decltype**(t1 + t2)
{return t1+t2;
}
auto v = compose(2, 3.14); // v's type is double

auto与for配合使用

std::map<std::string, std::vector<int>> map;
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
map["one"] = v;for(const auto& kvp : map) 
{std::cout << kvp.first << std::endl;for(auto v : kvp.second){std::cout << v << std::endl;}
}int arr[] = {1,2,3,4,5};
for(int& e : arr) 
{e = e*e;
}

std::lambda

“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。

C++11 的 lambda 表达式规范如下:

[ capture ] ( params ) mutable exception attribute -> ret { body } (1) [ capture ] ( params ) -> ret { body } (2) [ capture ] ( params ) { body } (3) [ capture ] { body } (4) 其中

(1) 是完整的 lambda 表达式形式, (2) const 类型的 lambda 表达式,该类型的表达式不能改捕获("capture")列表中的值。 (3)省略了返回值类型的 lambda 表达式,但是该 lambda 表达式的返回类型可以按照下列规则推演出来: 如果 lambda 代码块中包含了 return 语句,则该 lambda 表达式的返回类型由 return 语句的返回类型确定。 如果没有 return 语句,则类似 void f(...) 函数。 省略了参数列表,类似于无参函数 f()。

[] // 不引用外部变量 [x, &y] // x引用方式 ,y 传值 [&] // 任何使用的外部变量都是引用方式。 [=] // 任何被使用到的外部都是传值方式。 [&, x] // 除x传值以外其他的都以引用方式。 [=, &z] // 除z引用以外其他的都是以传值方式使用。

int main()
{std::vector<int> c { 1,2,3,4,5,6,7 };int x = 5;c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; } ), c.end());std::cout << "c: ";for (auto i: c) {std::cout << i << ' ';}std::cout << '\n';// 可以用auto 接收一个lambda 表达式。auto func1 = [](int i) { return i+4; };std::cout << "func1: " << func1(6) << '\n'; // std::function 也可以接收lambda 表达式。std::function<int(int)> func2 = [](int i) { return i+4; };std::cout << "func2: " << func2(6) << '\n'; std::function<int()> func3 = [x]{return x;};std::cout << "func3: " << func3() << '\n';std::vector<int> someList = {1,2,3};  //这里是c++11int total = 0;double sum = 0.0f;std::for_each(someList.begin(), someList.end(), [&total](int x) { total += x; });std::cout << total << '\n';std::for_each(someList.begin(), someList.end(), [&](int x){ total += x; sum += x;});std::cout << total << '\n';std::cout << sum << '\n';//再写一种简单的lambda[](){std::cout<<"就地展开的lambda\n";}();}

bind

std::bind是STL实现函数组合概念的重要手段,std::bind绑定普通函数(函数指针)、lambda表达式、成员函数、成员变量、模板函数等

#include <iostream>
#include <functional>void f(int n1, int n2, int n3, const int& n4, int n5)
{std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}int g(int n1)
{return n1;
}struct Foo {void print_sum(int n1, int n2){std::cout << n1+n2 << '\n';}static void static_func(std::function<int(int)> f,int n){std::cout<<"call static_func\n";std::cout<<"f(n):\t"<<f(n)<<"\n";}int data = 10; //c++11 支持声明是就初始化值
};int main()
{using namespace std::placeholders;// std::cref(n) 表示要把n以引用的方式传入  int n = 7;auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);n = 10;f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused// 绑定一个子表达式,用_3替换了 其他位置的变量// std::bind(g, _3) 在这里已经表示intauto f2 = std::bind(f, _4, std::bind(g, _4), _4, 4, 5);f2(10, 11, 12 ,13);// 绑定成员函数Foo foo;auto f3 = std::bind(&Foo::print_sum, foo, 95, _1);f3(5);// 绑定成员变量auto f4 = std::bind(&Foo::data, _1);std::cout << f4(foo) << '\n';// 绑定静态成员函数auto f5 = std::bind(&Foo::static_func,g,_1);f5(3);
}

std::function

通过std::function对C++中各种可调用实体(普通函数、Lambda表达式、函数指针、以及其它函数对象等)的封装,形成一个新的可调用的std::function对象;让我们不再纠结那么多的可调用实体。

转换后的std::function对象的参数能转换为可调用实体的参数; 可调用实体的返回值能转换为std::function对象的返回值。 std::function对象最大的用处就是在实现函数回调(实际工作中就是用到了这一点),使用者需要注意,它不能被用来检查相等或者不相等,但是可以与NULL或者nullptr进行比较。

#include <functional>
#include <iostream>
using namespace std;std::function< int(int)> Functional;// 普通函数
int TestFunc(int a)
{
return a;
}// Lambda表达式
auto lambda = [](int a)->int{ return a; };// 仿函数(functor)
class Functor
{
public:
int operator()(int a)
{
return a;
}
};// 1.类成员函数
// 2.类静态函数
class TestClass
{
public:
int ClassMember(int a) { return a; }
static int StaticMember(int a) { return a; }
};int main()
{
// 普通函数
Functional = TestFunc;
int result = Functional(10);
cout << "普通函数:"<< result << endl;// Lambda表达式
Functional = lambda;
result = Functional(20);
cout << "Lambda表达式:"<< result << endl;// 仿函数
Functor testFunctor;
Functional = testFunctor;
result = Functional(30);
cout << "仿函数:"<< result << endl;// 类成员函数
TestClass testObj;
Functional = std::bind(&TestClass::ClassMember, testObj, std::placeholders::_1);
result = Functional(40);
cout << "类成员函数:"<< result << endl;// 类静态函数
Functional = TestClass::StaticMember;
result = Functional(50);
cout << "类静态函数:"<< result << endl;return 0;
}

initializer_list

过往,我们这样给vector赋值:

std::vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);

需要感谢的是,C++11让你更方便。

std::vector v = { 1, 2, 3, 4 };

这就是所谓的initializer list。更进一步,有一个关键字叫initializer list

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <typeinfo> class MyNumber
{
public:MyNumber(const std::initializer_list<int> &v) {for (auto itm : v) {mVec.push_back(itm);}}void print() {for (auto itm : mVec) {std::cout << itm << " ";}}
private:std::vector<int> mVec;
};class Test {
public:void show(){for(auto kv : nameToBirthday){std::cout<<"key:\t"<<kv.first<<"\tvalue:\t"<<kv.second<<"\n";}}
private:static std::map<std::string, std::string> nameToBirthday;
};
std::map<std::string,std::string> Test::nameToBirthday  = {{"lisi", "18841011"},{"zhangsan", "18850123"},{"wangwu", "18870908"},{"zhaoliu", "18810316"}
};class CompareClass 
{
public:CompareClass (int,int){std::cout<<"call old const\n";}CompareClass (std::initializer_list <int> ){std::cout<<"call initializer_list const\n";}
};int main()
{MyNumber m = { 1, 2, 3, 4 };m.print();  // 1 2 3 4Test t;t.show(); std::map<int,int> ii_map = {{1,1},{2,2}};CompareClass foo {10,20};  // calls initializer_list ctorCompareClass bar (10,20);  // calls first constructor for(auto kv : ii_map){std::cout<<"key:\t"<<typeid(kv.first).name()<<"\n";}return 0;
}

thread

http://blog.csdn.net/tujiaw/article/details/8245130

#include <thread>
void my_thread()
{puts("hello, world");
}int main(int argc, char *argv[])
{std::thread t(my_thread);t.join();system("pause");return 0;
}

编译命令 g++ -std=c++11 thread0.cpp -o thread0 -lpthread

实例化一个线程对象t,参数mythread是一个函数,在线程创建完成后将被执行,t.join()等待子线程mythread执行完之后,主线程才可以继续执行下去,此时主线程会释放掉执行完后的子线程资源。

#include <iostream>
#include <stdlib.h>
#include <thread>
#include <string>
#include <unistd.h>void my_thread(int num, const std::string& str)
{std::cout << "num:" << num << ",name:" << str << std::endl;
}int main(int argc, char *argv[])
{int num = 1234;std::string str = "tujiaw";std::thread t(my_thread, num, str);t.detach(); //子线程从主线程中分离出去
//    sleep(1); return 0;
}

互斥量 多个线程同时访问共享资源的时候需要需要用到互斥量,当一个线程锁住了互斥量后,其他线程必须等待这个互斥量解锁后才能访问它。thread提供了四种不同的互斥量: 独占式互斥量non-recursive (std::mutex) 递归式互斥量recursive (std::recursivemutex) 允许超时的独占式互斥量non-recursive that allows timeouts on the lock functions(std::timedmutex) 允许超时的递归式互斥量recursive mutex that allows timeouts on the lock functions (std::recursivetimedmutex)

#include <iostream>
#include <stdlib.h>
#include <thread>
#include <string>
#include <mutex>int g_num = 0;
std::mutex g_mutex;void thread1()
{g_mutex.lock();     //线程加锁g_num = 10;for (int i=0; i<10; i++){std::cout << "thread1:" << g_num <<"\tthread id:\t"<< std::this_thread::get_id() << std::endl;}g_mutex.unlock();
}void thread2()
{std::lock_guard<std::mutex> lg(g_mutex); //自动锁g_num = 20;for (int i=0; i<10; i++){std::cout << "thread2:" << g_num <<"\tthread id:\t"<< std::this_thread::get_id() << std::endl;}
}int main(int argc, char *argv[])
{std::thread t1(thread1);std::thread t2(thread2);if(t1.joinable()) t1.join();
//    t1.join();
//    std::thread t3 = t2; //thread 对象禁止复制。 thread& operator= (const thread&) = delete; std::thread t3 = std::move(t2);if(t3.joinable()) t3.join();return 0;
}

std::thread 不仅能实现函数的绑定,成员函数,仿函数都可以。至于lambda 我就没有试过了。

简单的线程池实现

#include <iostream>
#include <stdlib.h>
#include <functional>
#include <thread>
#include <string>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <memory>
#include <assert.h>
#include <algorithm>
#include <queue>class ThreadPool
{public:typedef std::function<void()> Task;ThreadPool(int num): num_(num), maxQueueSize_(0), running_(false){}~ThreadPool(){if (running_) {stop();}}ThreadPool(const ThreadPool&) = delete;void operator=(const ThreadPool&) = delete;void setMaxQueueSize(int maxSize){maxQueueSize_ = maxSize;}void start(){assert(threads_.empty());running_ = true;threads_.reserve(num_);for (int i = 0; i<num_; i++) {threads_.push_back(std::thread(std::bind(&ThreadPool::threadFunc, this)));}}void stop(){{std::unique_lock<std::mutex> ul(mutex_);running_ = false;notEmpty_.notify_all();}for (auto &iter : threads_) {iter.join();}}void run(const Task &t){if (threads_.empty()) {t();}else {std::unique_lock<std::mutex> ul(mutex_);while (isFull()) {notFull_.wait(ul);}assert(!isFull());queue_.push_back(t);notEmpty_.notify_one();}}private:bool isFull() const{return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_;}void threadFunc(){while (running_) {Task task(take());if (task) {std::lock_guard<std::mutex> lg(mutex_out); //自动锁printf("thread id:%d\n", std::this_thread::get_id());task();printf("thread id:%d\n", std::this_thread::get_id());}}}Task take(){std::unique_lock<std::mutex> ul(mutex_);while (queue_.empty() && running_) {notEmpty_.wait(ul);}Task task;if (!queue_.empty()) {task = queue_.front();queue_.pop_front();if (maxQueueSize_ > 0) {notFull_.notify_one();}}return task;}private:int num_;std::mutex mutex_;std::mutex mutex_out;std::condition_variable notEmpty_;std::condition_variable notFull_;std::vector<std::thread> threads_;std::deque<Task> queue_;size_t maxQueueSize_;bool running_;
};void fun()
{printf("[id:%d] hello, world!\n", std::this_thread::get_id());
}int main()
{{printf("main thread id:%d\n", std::this_thread::get_id());ThreadPool pool(3);pool.setMaxQueueSize(100);pool.start();//std::this_thread::sleep_for(std::chrono::milliseconds(3000));for (int i = 0; i < 1000; i++) {pool.run(fun);}std::this_thread::sleep_for(std::chrono::milliseconds(3000));}return 0;
}

atomic

原子操作

#include <thread>
#include <atomic> 
#include <iostream>
#include <time.h>
#include <mutex>
using namespace std;
// 全局的结果数据 
//long total = 0; 
std::atomic_long total(0);
//std::mutex g_mutex;// 点击函数
void click()
{for(int i=0; i<1000000;++i){// 对全局数据进行无锁访问 
//        std::lock_guard<std::mutex> lg(g_mutex); //自动锁total += 1;     }
}int main(int argc, char* argv[])
{// 计时开始clock_t start = clock();// 创建100个线程模拟点击统计std::thread threads[100];for(int i=0; i<100;++i) {threads[i] = std::thread(click);}for(auto& t : threads){t.join();}// 计时结束clock_t finish = clock();// 输出结果cout<<"result:"<<total<<endl;cout<<"duration:"<<finish -start<<"us"<<endl;return 0;
}

shared_ptr

这个sharedptr 相信大家都已经在boost中用过了。这里就不用详细介绍了,反正是在能用原始指针的地方就能替换成 sharedptr。 #include #include

struct Foo {Foo() { std::cout << "constructor Foo...\n"; }Foo(Foo&f) {std::cout<<"copy constructor Foo...\n";}void show(int i){std::cout<<"show Foo "<<i<<"\n";}~Foo() { std::cout << "~Foo...\n"; }
};struct D { void operator()(Foo* p) const {std::cout << "Call delete for Foo object...\n";delete p;}
};void needptr( Foo* fn,int i)
{fn->show(i); 
}void needshptr(std::shared_ptr<Foo> shptr,int i)
{shptr->show(i);std::cout<< shptr.use_count()<<'\n';
}
int main()
{   // 只形成一个指针std::shared_ptr<Foo> sh1;   //needptr(sh1.get(),1);auto shfn =  std::make_shared<Foo>(); // 调用构造函数shfn->show(2);  // std::shared_ptr<Foo> sh2(new Foo);std::shared_ptr<Foo> sh3(sh2);std::cout << sh2.use_count() << '\n';std::cout << sh3.use_count() << '\n';needshptr(sh3,3);std::cout << sh3.use_count() << '\n';//constructor with object and deleterstd::shared_ptr<Foo> sh4(new Foo, D());
}

override和final关键字

override 强制检查虚函数 final 禁止虚函数继续重写

高质量C++C 编程指南 访问密码 5de8

override 用法

#include <string>
#include <iostream>
#include <stdint.h>
#include <stdio.h>
class G
{public:virtual void func(double a){   std::cout<<"G::func="<<a<<std::endl;}   
};class H:public G
{public:int a;int b;void  test(){   std::cout<<"Normal func"<<std::endl;}   // 同名函数被隐藏了virtual void func(int a) //override //c++11 中添加这个关键字就能解决这一问题{   std::cout<<"H::func="<<a<<std::endl;}   
};typedef void (*FuncD)(double a); typedef void (*FuncI)(int a); typedef void (H::*Func)();//节选自 林锐博士的 《高质量C++C 编程指南》 8.2 章节
//重载的特征:
//  1、处在相同的空间中,即相同的范围内。
//  2、函数名相同。
//  3、参数不同,即参数个数不同,或相同位置的参数类型不同。
//  4、virtual 关键字对是否够成重载无任何影响。
//  每个类维护一个自己的名字空间,即类域,所以派生类跟基类处于不同的空间之中,因些,虽然派生类自动继承了基类的成员变量及成员函数,但基类的函数跟派生类的函数不可能直接够成函数重载,因为它们处于两个不同的域。
//
//  隐藏规则:
//  1、派生类的函数跟基类的函数同名,但是参数不同,此时,不论有没有virtual关键字,基类函数将被隐藏。
//  2、派生类的函数跟基类的函数同名,且参数也样,但基类没有virtual关键字,此时基类函数也将被隐藏。//隐藏规则的底层原因其实是C++的名字解析过程。//  在继承机制下,派生类的类域被嵌套在基类的类域中。派生类的名字解析过程如下:
//  1、首先在派生类类域中查找该名字。
//  2、如果第一步中没有成功查找到该名字,即在派生类的类域中无法对该名字进行解析,则编译器在外围基类类域对查找该名字的定义。
int main(int argc,char *argv[])
{H *h=new H;printf("%x\n",h);printf("%x\n",&H::test);printf("%x\n",&H::func);Func func=&H::test;(h->*func)();FuncD fund=(FuncD)(*(intptr_t*)*(intptr_t*)(h));FuncI funi=(FuncI)(*((intptr_t*)*(intptr_t*)(h)+1));printf("fund=%x\n",(intptr_t*)*(intptr_t*)(h));printf("funi=%x\n",((intptr_t*)*(intptr_t*)(h)+1));fund(10.1);funi(10);fund((G*)h,10.1);   //需要绑定一个this指针,同时也把封装性破坏了。funi(h,10);h->func(5);h->func(5.5);((g*)h)->func(5.5);h->G::func(5.5); return 0;
}

final 的用法

#include <iostream>
using namespace std;class MathObject{public:virtual double Arith() = 0;
//        virtual void Print() final = 0 ; // 这样写会造成凡是派生自它的子类都无法创建对象virtual void Print() = 0 ;virtual void Print2(){cout<<"this is Print2()\n";};
};class Printable : public MathObject{public:double Arith() = 0;void Print() final// 在C++98中我们无法阻止该接口被重写{cout << "Output is: " << Arith() << endl;}
};class Add2 final: public Printable {public:Add2(double a, double b): x(a), y(b) {}double Arith() override final{ return x + y; }private:double x, y;
};class Mul3 : public Printable {public:Mul3(double a, double b, double c): x(a), y(b), z(c) {}double Arith() { return x * y * z; }
//        void Print() 这里无法在改写这个函数
//        {
//            cout<<"Mul3 Print\n";
//        }private:double x, y, z;
};int main()
{Add2 add2(2,3);cout<<"add2.Arith()"<<add2.Arith()<<'\n';add2.Print();Mul3 mul3(1,2,3);mul3.Print();return 0;
}

delete default

设置默认构造函数时使用。在类中定义了构造函数后,还想继续使用默认构造函数,则可以在函数成员列表后添加 =default 。

可以使用在不允许使用复制构造函数和赋值构造函数上,则可以在函数成员列表后添加 =delete表示不定义。

#include <iostream>class NonCopyable
{
public:NonCopyable & operator=(const NonCopyable&) = delete;NonCopyable(const NonCopyable&) = delete;NonCopyable(int i){};NonCopyable() = default; // 不相当于用户在写一个 NonCopyable(void){};NonCopyable(double) = delete;void* operator new(size_t) = delete;
//    void* operator new[](size_t) = delete;//private:int m_i;};int main()
{NonCopyable nc;
//    NonCopyable* pnc = new NonCopyable();NonCopyable *pncs = new NonCopyable[10]();std::cout<<sizeof(NonCopyable::m_i)<<std::endl;     //sizeof 可以直接计算成员变量的大小,成员在外部必须可见。return 0;
}

正则

主类

这些类封装了一个正则表达式和目标内的字符序列匹配正则表达式的结果.

basic_regex (C++11) 正则表达式对象 (类模板)

算法

使用这些功能应用正则表达式封装在一个正则表达式的字符序列目标.. regexmatch 尝试匹配正则表达式的整个字符序列 (函数模板) regexsearch 尝试匹配正则表达式的字符序列的任何部分 函数模板) regex_replace 以格式化的替换文本来替换正则表达式匹配的地方(函数模板)

正则规则

#include <iostream>
#include <iterator>
#include <string>
#include <regex>
#include <fstream>
#include <iterator>
#include <vector>
using VSS = std::vector<std::pair<std::string,std::string>> ;bool regex_search_all(std::string s,VSS& o , std::string reg_str)
{std::regex r(reg_str);std::smatch m;bool ret = false;while(std::regex_search(s,m,r)){o.push_back(std::move(std::make_pair(m[0].str(),m[1].str())));s = m.suffix().str();ret = true;}return ret;
}
int main()
{std::string s = "Some people, when confronted with a problem, think ""\"I know, I'll use regular expressions.\" ""Now they have two problems.";// 正则匹配std::regex self_regex("REGULAR EXPRESSIONS",std::regex_constants::ECMAScript | std::regex_constants::icase);if (std::regex_search(s, self_regex)) {std::cout << "Text contains the phrase 'regular expressions'\n";}std::ifstream in("360_20160114.xml", std::ios::in);std::istreambuf_iterator<char> beg(in), end;std::string strdata(beg, end);in.close();std::regex word_regex("(<pic_url>)\\s*(http://.*)\\s*(</pic_url>)");auto words_begin = std::sregex_iterator(strdata.begin(), strdata.end(), word_regex);auto words_end = std::sregex_iterator();std::cout << "Found " << std::distance(words_begin, words_end) << " words\n";for (std::sregex_iterator i = words_begin; i != words_end; ++i) {std::smatch match = *i;std::cout << "  " << match.str() << '\n';}//正则捕获std::string reg_str("<pic_url>\\s*(http://.*)\\s*</pic_url>");VSS vss;regex_search_all(strdata,vss,reg_str);for(auto kv : vss){std::cout<<kv.first<<'\t'<<kv.second<<'\n';}std::regex url_regex(reg_str);std::smatch m;while(std::regex_search(strdata,m,url_regex)){for(auto beg = m.begin(); beg != m.end();beg++){std::cout<<"匹配上:"<<beg->str()<<"\n";}strdata = m.suffix().str();}//正则替换std::regex long_word_regex("(\\w{7,})");std::string new_s = std::regex_replace(s, long_word_regex, "[$&]");std::cout << new_s << '\n';
}

代码2 #include #include #include

int main()
{std::string fnames[] = {"foo.txt", "bar.txt", "baz.dat", "zoidberg"};std::regex pieces_regex("([a-z]+)\\.([a-z]+)");std::smatch pieces_match; for (const auto &fname : fnames) {if (std::regex_match(fname, pieces_match, pieces_regex)) {std::cout << fname << '\n';for (size_t i = 0; i < pieces_match.size(); ++i) {std::ssub_match sub_match = pieces_match[i];std::string piece = sub_match.str();std::cout << "  submatch " << i << ": " << piece << '\n';}   }   }   
}

输出

foo.txtsubmatch 0: foo.txtsubmatch 1: foosubmatch 2: txt
bar.txtsubmatch 0: bar.txtsubmatch 1: barsubmatch 2: txt
baz.datsubmatch 0: baz.datsubmatch 1: bazsubmatch 2: dat

c++11 中vector 的新用法

修正过剩的容量

#include <vector>
#include <iostream>void fun_old()
{const int NUM = 1000;std::vector<int*> vec( NUM, nullptr );for(auto& e : vec){e = new int(42);}std::cout << "origin capacity: " << vec.capacity() << std::endl;std::cout << "first elem addr is " << vec[0] << std::endl;for(auto it = vec.begin() + 2; it != vec.end() ; it++){delete *it;*it = nullptr;}vec.erase(vec.begin() + 2, vec.end());std::vector<int*>( vec ).swap( vec );std::cout << "capacity after erase: " << vec.capacity() << std::endl;std::cout << "first elem addr is " << vec[0] << std::endl;for(auto e : vec){delete e;}
}void fun_new()
{const int NUM = 1000;std::vector<int*> vec( NUM, nullptr );for(auto& e : vec){e = new int(42);}std::cout << "origin capacity: " << vec.capacity() << std::endl;std::cout << "first elem addr is " << vec[0] << std::endl;for(auto it = vec.begin() + 2; it != vec.end() ; it++){delete *it;*it = nullptr;}vec.erase( vec.begin() + 2, vec.end() );vec.shrink_to_fit();std::cout << "capacity after erase: " << vec.capacity() << std::endl;std::cout << "first elem addr is " << vec[0] << std::endl;for(auto e : vec){delete e;}
}
int main()
{fun_old();fun_new();
}

直接构造元素

#include <vector>
#include <string>
#include <iostream>
using namespace std;
class Person
{public:Person( string name ) : name_( name ) { }Person( const Person &other ) : name_( other.name_ ) {cout << "in copy constructor with name is " << name_ << endl;}Person(Person&& other) : name_( std::move(other.name_)){cout << "in move constructor with name is " << name_ << endl;}private:string name_;
};int main()
{std::vector<Person> vec;vec.reserve( 10 );cout<<"vec.push_back(Person(\"senlin\" ) )\n";vec.push_back( Person( "senlin" ) );cout<<"vec.push_back( p )\n";Person p( "zongming" );vec.push_back( p );cout<<"vec.push_back(Person(\"zhaoxiaobiao\"))\n";vec.push_back(Person("zhaoxiaobiao"));cout<<"vec.push_back(std::move(p))\n";vec.push_back(std::move(p));vec.push_back(std::move(Person("move")));cout<<"vec.emplace_back(\"zhaoxiaobiao\")\n";vec.emplace_back("zhaoxiaobiao");
}

虽然华丽,但也让人眼花缭乱。

虽然华丽,但也让人眼花缭乱。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383748.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++仿函数 functor

https://www.cnblogs.com/decade-dnbc66/p/5347088.html内容整理自国外C教材先考虑一个简单的例子&#xff1a;假设有一个vector<string>&#xff0c;你的任务是统计长度小于5的string的个数&#xff0c;如果使用count_if函数的话&#xff0c;你的代码可能长成这样&#…

Ubuntu软件更新失败

刚安装好Ubuntu以后需要将系统的软件都更新一下&#xff0c;但是遇到一个问题就是下载仓库信息失败&#xff0c;大概是这个样子的错误&#xff1a; 经国遇到这样的问题可以试一下下面这个命令&#xff1a; sudo rm -rf /var/lib/apt/lists/* sudo apt-get update参考网址&…

getsockname函数与getpeername函数的使用

https://www.tuicool.com/articles/V3Aveygetsockname和getpeername函数 getsockname函数用于获取与某个套接字关联的本地协议地址 getpeername函数用于获取与某个套接字关联的外地协议地址 定义如下&#xff1a;[cpp] view plaincopy#include<sys/socket.h> int gets…

Linux命令【一】基本命令

shell命令和bash命令相同&#xff0c;指的是命令解析器 快捷键 history 所有的历史命令ctrl P 向上滚动命令 ctrl N 向下滚动命令 ctrlB将光标向前移动 ctrlF将光标向后移动 ctrlA移动到命令行头部 ctrlE移动到命令行尾部 光标删除操作&#xff1a;删除光标前面字符ctrlh或…

剑指offer面试题:替换空格

https://blog.csdn.net/yanxiaolx/article/details/52235212题目&#xff1a;请实现一个函数&#xff0c;把字符串中的每个空格替换成“%20”。例如输入“We are happy.”&#xff0c;则输出“We%20are%20happy.”。解析&#xff1a;时间复杂度为O(n)的解法。完整代码及测试用例…

数据库原理及应用【一】引言

什么是数据库&#xff1a;一个大规模的集成的数据集合 作用&#xff1a;描述现实世界的实体(entities)以及实体之间的关系 管理数据库的系统软件&#xff1a;DBMS 文件是一个平滑的字符流&#xff0c;无法完成信息的检索和管理 数据&#xff08;data&#xff09;:用来描述现…

用c++模拟实现一个学生成绩管理系统

https://blog.csdn.net/yanxiaolx/article/details/53393437题目&#xff1a;用c模拟实现一个学生成绩的信息管理系统&#xff0c;要求能添加、删除、修改、查看和保存学生的信息等功能 源代码如下:[cpp] view plaincopy#define _CRT_SECURE_NO_WARNINGS #include<iostr…

Python3列表

操作&#xff1a;索引、切片、加、乘、检查成员、确定序列长度、确定最大最小元素 定义&#xff1a; 列表名 [元素]下标列表名[x] 截取:列表名[x:y] 更新&#xff1a; list[x]y 或者使用append()方法添加列表项删除&#xff1a; del list[x]常用操作&#xff1a; 截取与…

Linux惊群效应详解(最详细的了吧)

https://blog.csdn.net/lyztyycode/article/details/78648798?locationNum6&fps1 linux惊群效应详细的介绍什么是惊群&#xff0c;惊群在线程和进程中的具体表现&#xff0c;惊群的系统消耗和惊群的处理方法。1、惊群效应是什么&#xff1f;惊群效应也有人叫做雷鸣群体效应…

epoll原理详解(最清晰)

https://blog.csdn.net/lyztyycode/article/details/79491419我只是把内容搬运过来做个记录&#xff0c;方便自己以后回头看。第一部分&#xff1a;select和epoll的任务关键词&#xff1a;应用程序 文件句柄 用户态 内核态 监控者要比较epoll相比较select高效在什么地方&#x…

Ubuntu卸载软件

用过使用dpkg软件管理工具得到所有已经安装的软件&#xff0c;如果不清楚软件的全名可以使用grep命令进行查找 然后再使用sudo apt-get remove --purge 软件名卸载软件&#xff08;--purge参数会删除配置文件&#xff0c;删的干净一些&#xff09; 例如&#xff1a;

一个重要且实用的signal---SIGCHLD

https://blog.csdn.net/lyztyycode/article/details/78150805SIGCHLD(修改)因为笔者之前的文章里面有错误&#xff0c;今天发现&#xff0c;立马做个修改。在下面我的一段关于sigchld信号相对于直接调用wait函数的好处时&#xff0c;我说调用wait函数要一直检测子进程是否执行完…

Python3函数和代码复用

函数的定义 def 函数名([参数列表]):注释函数体注意事项 函数形参不需要声明类型&#xff0c;可以使用return语句在结束函数执行的同时返回任意类型的值&#xff0c;函数返回值类型与return语句返回表达式i的类型一致 即使该函数不需要接受任何参数&#xff0c;也必须保留一堆…

一文说尽C++赋值运算符重载函数(operator=)

http://www.cnblogs.com/zpcdbky/p/5027481.html在前面&#xff1a;关于C的赋值运算符重载函数(operator)&#xff0c;网络以及各种教材上都有很多介绍&#xff0c;但可惜的是&#xff0c;内容大多雷同且不全面。面对这一局面&#xff0c;在下在整合各种资源及融入个人理解的基…

Python a和a[:]的区别

简单来讲a[:]是深复制&#xff0c;a是浅复制&#xff0c;相当于赋值a的话是赋值了指针&#xff0c;赋值a[:]相当于复制了a对应的那段空间 例如&#xff1a; a [1,1,1,1,1,1]for x in a:if x1:a.remove(x)print(a)运行结果&#xff1a; remove操作是移除序列中第一个x元素。…

Linux系统【二】exec族函数及应用

文件描述符 文件描述符表是一个指针数组&#xff0c;文件描述符是一个整数。 文件描述符表对应的指针是一个结构体&#xff0c;名字为file_struct&#xff0c;里面保存的是已经打开文件的信息 需要注意的是父子进程之间读时共享&#xff0c;写时复制的原则是针对物理地址而言…

白话C++系列(27) -- RTTI:运行时类型识别

http://www.cnblogs.com/kkdd-2013/p/5601783.htmlRTTI—运行时类型识别 RTTI&#xff1a;Run-Time Type Identification。 那么RTTI如何来体现呢&#xff1f;这就要涉及到typeid和dynamic_cast这两个知识点了。为了更好的去理解&#xff0c;那么我们就通过一个例子来说明。这个…

使用头文件的原因和规范

原因 通过头文件来调用库功能。在很多场合&#xff0c;源代码不便&#xff08;或不准&#xff09;向用户公布&#xff0c;只 要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库 功能&#xff0c;而不必关心接口怎么实现的。编译器会从库中提取相应…

转圈踢人问题

https://www.cnblogs.com/lanxuezaipiao/p/3339603.html 有N个人围一圈依次报数&#xff0c;数到3的倍数的人出列&#xff0c;问当只剩一个人时他原来的位子在哪里&#xff1f; 解答&#xff1a;经典的转圈踢人问题&#xff0c;好吧专业一点&#xff0c;约瑟夫环问题&#xff0…

Python3常用数据结构

Python3中有三种组合数据类型&#xff0c;分别为&#xff1a; 序列类型&#xff1a;字符串&#xff08;str&#xff09;、元组&#xff08;tuple&#xff09;、列表&#xff08;list&#xff09;集合类型&#xff1a;集合&#xff08;set&#xff09;映射类型&#xff1a;字典…