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

c++11新特性


举着火把寻找电灯

enter description here


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


T&& 右值引用 std::move

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

int main()
{
    int i = 42;
    int &r = i; // ok: r refers to i
    int &&rr = i;   // error: cannot bind an rvalue reference to an lvalue
    int &r2 = i * 42;   // error: i * 42 is an rvalue
    const int &r3 = i * 42; // ok: we can bind a reference to  const  to an rvalue
    int &&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 @0x603030
    return 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++11
    int 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) 在这里已经表示int
    auto 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 4

    Test t;
    t.show(); 

    std::map<int,int> ii_map = {{1,1},{2,2}};

    CompareClass foo {10,20};  // calls initializer_list ctor
    CompareClass 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 deleter
    std::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.txt
  submatch 0: foo.txt
  submatch 1: foo
  submatch 2: txt
bar.txt
  submatch 0: bar.txt
  submatch 1: bar
  submatch 2: txt
baz.dat
  submatch 0: baz.dat
  submatch 1: baz
  submatch 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");
}

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

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

【广告】 我的博客地址

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页