博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c++11 你需要知道这些就够了
阅读量:4094 次
发布时间:2019-05-25

本文共 22146 字,大约阅读时间需要 73 分钟。

http://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 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 
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 
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
> map;std::vector
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
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
func2 = [](int i) { return i+4; }; std::cout << "func2: " << func2(6) << '\n'; std::function
func3 = [x]{return x;}; std::cout << "func3: " << func3() << '\n'; std::vector
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 
#include
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
f,int n) { std::cout<<"call static_func\n"; std::cout<<"f(n):\t"<
<<"\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 
#include
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 
#include
#include
#include
#include
class MyNumber{public: MyNumber(const std::initializer_list
&v) { for (auto itm : v) { mVec.push_back(itm); } } void print() { for (auto itm : mVec) { std::cout << itm << " "; } }private: std::vector
mVec;};class Test {public: void show() { for(auto kv : nameToBirthday) { std::cout<<"key:\t"<
<<"\tvalue:\t"<
<<"\n"; } }private: static std::map
nameToBirthday;};std::map
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
) {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
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"<
<<"\n"; } return 0;}

thread

#include 
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 
#include
#include
#include
#include
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 
#include
#include
#include
#include
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
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 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class ThreadPool{ public: typedef std::function
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
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
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
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
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
threads_; std::deque
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 
#include
#include
#include
#include
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
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:"<
<

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 "<<<"\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
shptr,int i){ shptr->show(i); std::cout<< shptr.use_count()<<'\n';}int main(){ // 只形成一个指针 std::shared_ptr
sh1; // needptr(sh1.get(),1); auto shfn = std::make_shared
(); // 调用构造函数 shfn->show(2); // std::shared_ptr
sh2(new Foo); std::shared_ptr
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
sh4(new Foo, D());}

override和final关键字

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

override 用法

#include 
#include
#include
#include
class G{ public: virtual void func(double a) { std::cout<<"G::func="<
<
*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 
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()"<
<<'\n'; add2.Print(); Mul3 mul3(1,2,3); mul3.Print(); return 0;}

delete default

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

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

#include 
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<
<

正则

主类

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

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

算法

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

#include 
#include
#include
#include
#include
#include
#include
using VSS = std::vector
> ;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
beg(in), end; std::string strdata(beg, end); in.close(); std::regex word_regex("(
)\\s*(http://.*)\\s*(
)"); 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("
\\s*(http://.*)\\s*
"); VSS vss; regex_search_all(strdata,vss,reg_str); for(auto kv : vss) { std::cout<
<<'\t'<
<<'\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<<"匹配上:"<
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: txtbar.txt  submatch 0: bar.txt  submatch 1: bar  submatch 2: txtbaz.dat  submatch 0: baz.dat  submatch 1: baz  submatch 2: dat

c++11 中vector 的新用法

修正过剩的容量

#include 
#include
void fun_old(){ const int NUM = 1000; std::vector
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
( 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
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 
#include
#include
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
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");}

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

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

你可能感兴趣的文章
聊聊gcc参数中的-I, -L和-l
查看>>
[C++基础]034_C++模板编程里的主版本模板类、全特化、偏特化(C++ Type Traits)
查看>>
C语言内存检测
查看>>
Linux epoll模型
查看>>
Linux select TCP并发服务器与客户端编程
查看>>
Linux系统编程——线程池
查看>>
基于Visual C++2013拆解世界五百强面试题--题5-自己实现strstr
查看>>
Linux 线程信号量同步
查看>>
C++静态成员函数访问非静态成员的几种方法
查看>>
类中的静态成员函数访问非静态成员变量
查看>>
C++学习之普通函数指针与成员函数指针
查看>>
C++的静态成员函数指针
查看>>
Linux系统编程——线程池
查看>>
yfan.qiu linux硬链接与软链接
查看>>
Linux C++线程池实例
查看>>
shared_ptr简介以及常见问题
查看>>
c++11 你需要知道这些就够了
查看>>
c++11 你需要知道这些就够了
查看>>
shared_ptr的一些尴尬
查看>>
C++总结8——shared_ptr和weak_ptr智能指针
查看>>