标签:c++primer
【 声明:版权所有,转载请标明出处,请勿用于商业用途。 联系信箱:libin493073668@sina.com】
12.1 动态内存与智能指针
1.在C++中,动态内存的管理是通过一对运算符来完成:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。
2.
shared_ptr允许多个指针指向同一个对象;unique_ptr则“独占”所指向的对象。标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。
3.
shared_ptr和unique_ptr都支持的操作
shared_ptr<T> sp
unique_ptr<T> up 空智能指针,可以指向类型为T的对象
p 将p用作一个条件判断,若p指向一个对象,则为true
*p 解引用p,获得它指向的对象
p->mem 等价于(*p).mem
p.get() 返回p中保存的指针。要小心使用,若智能指针释放了其对象,返回的指针所指向的对象也就消失了。
swap(p,q)
p.swap(q) 交换p和q中的指针
4.
shared_ptr独有的操作
make_shared<T>(args) 返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化对象。
make_shared<T>p(q) p是shared_ptr q的拷贝;此操作会递增q中的计数器。q中的指针必须能转换为T*
p = q p和q都是shared_ptr,所保存的指针必须能相互转换。此操作会递减p的引用计数,递增q的引用计数;若p的引用计数变为0,则将其管理的原内存释放。
p.unique() 若p.use_count()为1,返回true;否则返回false
p.use_count() 返回与p共享对象的智能指针数量;可能很慢,主要用于测试
5.
由内置指针(而不是智能指针)管理的动态内存在被显式释放以前一直都会存在。
6.
定义和改变shared_ptr的其他方法
shared_ptr<T> p(q) p管理内置指针q所指向的对象;q必须指向new分配的内存,且能够转换为T*类型
shared_ptr<T> p(u) p从unique_ptr u那里接管了对象的所有权,将u置为空
shared_ptr<T> p(q,d) p接管了内置指针q所指向的对象的所有权。q必须能转换为T*类型。p将使用可调用对象d来代替delete
shared_ptr<T> p(p2,d) p是shared_ptr p2的拷贝,唯一的区别是p将用可调用对象d来代替delete
p.reset()
p.reset(q)
p.reset(q,d) 若p是唯一指向其对象的shared_ptr,reset会释放此对象。若传递了可选的参数内置指针q,会令p指向q,否则会将p置为空。若还传递了参数d,将会调用d而不是delete来释放q
7.
为了正确使用智能指针,我们必须坚持一些基本规范
⑴不使用相同的内置指针值初始化(或reset)多个智能指针
⑵不delete get()返回的指针
⑶不使用get()初始化或reset另一个智能指针
⑷如果你使用get()返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变成无效了
⑸如果你使用智能指针管理的资源不是new分配的内存,记住传递给它一个删除器
8.
unique_ptr操作
unique_ptr<T> u1
unique_ptr<T,p> u2 空unique_ptr,可以指向类型为T的对象。u1会使用delete来释放它的指针;u2会使用一个类型为D的可调用对象来释放它的指针
unique_ptr<T,p> u(d) 空unique_ptr,指向类型为T的对象,用类型为D的对象d代替delete
u = nullptr 释放u所指向的对象,将u置为空
u.release u放弃对指针的控制权,返回指针,并将u置为空
u.reset() 释放u指向的对象
u.reset(q)
u.reset(nullptr) 如果提供了内置指针q,令u指向这个对象;否则将u置为空
9.
weak_ptr操作
weak_ptr<T> w 空weak_ptr可以指向类型为T的对象
weak_ptr<T> w(sp) 与shared_ptr sp指向相同对象的weak_ptr。T必须能转换为sp指向的类型。
w = p p可以是一个shared_ptr或一个weak_ptr。赋值后w与p共享对象
w.reset() 将w置为空
w.use_count() 与w共享对象的shared_ptr的数量
w.expired() 若w.use_count()为0,返回true,否则返回false
w.lock() 如果expired为true,返回一个空shared_ptr;否则返回一个指向w的对象的shared_ptr
12.2 动态数组
1.动态数组并不是数组类型,而是得到一个数组元素类型的指针。
2.
指向数组的unique_ptr
指向数组的unique_ptr不支持成员访问运算符
其他unique_ptr操作不变
unique_ptr<T[]> u u可以指向一个动态分配的数组,数组元素类型为T
unique_ptr<T[]> u(p) u指向内置指针p所指向的动态分配的数组。p必须能转换为类型T*
u[i] 返回u拥有的数组中位置i处的对象,u必须指向一个数组
3.标准库allocator类定义在头文件memory中,它帮助我们将内存分配和对象构造分离开来。它提供一种类型感知的内存分配方法,它分配的内存是原始的,未构造的。
4.
标准库allocator类及其算法
allocator<T> a 定义了一个名为a的allocator对象,它可以为类型为T的对象分配内存
a.allocator(n) 分配一段原始的,未构造的内存,保存n个类型为T的对象
a.deallocate(p,n) 释放从T*指针p中地址开始的内存,这块内存保存了n个类型为T的对象;p必须是一个先前由allocate返回的指针,且n必须是p创建时所要求的大小。在调用deallocate之前,用户必须对每个在这块内存中创建的对象调用destory。
a.construct(p,args) p必须是一个类型为T*的指针,指向一块原始内存;arg被传递给类型为T的构造函数,用来在p指向的内存中构造一个对象
a.destroy(p) p为T*类型的指针,此算法对p指向的对象指向析构函数
5.
allocator算法
这些函数在给定目的位置创建元素,而不是由系统分配内存给它们。
uninitialized_copy(b,e,b2) 从迭代器b和e指出的输入范围中拷贝元素到迭代器b2指定的未构造的原始内存中。b2指向的内存必须足够大,能容纳输入序列中元素的拷贝
uninitialized_copy_n(b,n,b2)
从迭代器b指向的元素开始,拷贝n个元素到b2开始的内存中
uninitialized_fill(b,e,t)
在迭代器b和e指定的原始内存范围中创建对象,对象的值均为t的拷贝
uninitialized_fill_n(b,n,t) 从迭代器b指向的内存地址开始创建n个对象。b必须指向足够大的未构造的原始内存,能够容纳给定数量的对象
PS:部分练习答案
练习12.1
b2被销毁,但是b2里面的元素不会被销毁,所以b1,b2都有4个元素
练习12.2
ex12_02.h
#include <vector> #include <string> #include <initializer_list> #include <memory> #include <exception> using std::vector; using std::string; class StrBlob { public: using size_type = vector<string>::size_type; StrBlob():data(std::make_shared<vector<string>>()) {} StrBlob(std::initializer_list<string> il):data(std::make_shared<vector<string>>(il)) {} size_type size() const { return data->size(); } bool empty() const { return data->empty(); } void push_back(const string& t) { data->push_back(t); } void pop_back() { check(0,"pop_back on empty StrBlob"); data->pop_back(); } std::string& front() { check(0,"front on empty StrBlob"); return data->front(); } std::string& back() { check(0,"back on empty StrBlob"); return data->back(); } const std::string& front() const { check(0,"front on empty StrBlob"); return data->front(); } const std::string& back() const { check(0,"back on empty StrBlob"); return data->back(); } private: void check(size_type i,const string& msg) const { if(i>=data->size()) throw std::out_of_range(msg); } private: std::shared_ptr<vector<string>> data; };
#include <iostream> #include "ex12_02.h" int main() { const StrBlob csb{"one","two","three"}; StrBlob sb{"one","two","four"}; std::cout << csb.front() << " " << csb.back() << std::endl; sb.back() = "three"; std::cout << sb.front() << " " << sb.back() << std::endl; }
练习12.6
#include <iostream> #include <vector> #include <string> #include <memory> std::vector<int>* dynamic_vector_generator() { std::vector<int>* ptr_v = new std::vector<int>(); return ptr_v; } void dynamic_vector_processor(std::vector<int>* ptr_v) { int i; std::cout << "please enter:" << std::endl; while(std::cin >> i && i!=999) ptr_v->push_back(i); } void dynamic_vector_printer(std::vector<int>* ptr_v) { for(const auto& elem: *ptr_v) std::cout << elem << " "; std::cout << std::endl; } int main() { std::vector<int>* ptr_vi = dynamic_vector_generator(); dynamic_vector_processor(ptr_vi); dynamic_vector_printer(ptr_vi); delete ptr_vi; return 0; }
#include <iostream> #include <vector> #include <string> #include <memory> std::shared_ptr<std::vector<int>> dynamic_vector_generator_sptr() { return std::make_shared<std::vector<int>>(); } void dynamic_vector_processor_sptr(std::shared_ptr<std::vector<int>> sptr_vi) { int i; std::cout << "please enter:" << std::endl; while(std::cin >> i && i!=999) sptr_vi->push_back(i); } void dynamic_vector_printer_sptr(const std::shared_ptr<std::vector<int>> sptr_vi) { for(const auto& elem: *sptr_vi) std::cout << elem << " "; std::cout << std::endl; } int main() { auto sptr = dynamic_vector_generator_sptr(); dynamic_vector_processor_sptr(sptr); dynamic_vector_printer_sptr(sptr); return 0; }
#include <iostream> #include <string> #include <memory> struct connection { std::string ip; int port; connection(std::string ip_,int port_):ip(ip_),port(port_){} }; struct destination { std::string ip; int port; destination(std::string ip_,int port_):ip(ip_),port(port_){} }; connection connect(destination* pDest) { std::shared_ptr<connection> pConn(new connection(pDest->ip,pDest->port)); std::cout << "creating connection(" << pConn.use_count() << ")" << std::endl; return *pConn; } void disconnect(connection pConn) { std::cout << "connection close(" << pConn.ip << ":" << pConn.port << ")" << std::endl; } void end_connection(connection* pConn) { disconnect(*pConn); } void f(destination& d) { connection conn = connect(&d); std::shared_ptr<connection> p(&conn,end_connection); std::cout << "connection now(" << p.use_count() << ")" << std::endl; } int main() { destination dest("202.118.176.67",3316); f(dest); return 0; }
#include <iostream> #include <string> #include <memory> struct connection { std::string ip; int port; connection(std::string ip_,int port_):ip(ip_),port(port_){} }; struct destination { std::string ip; int port; destination(std::string ip_,int port_):ip(ip_),port(port_){} }; connection connect(destination* pDest) { std::shared_ptr<connection> pConn(new connection(pDest->ip,pDest->port)); std::cout << "creating connection(" << pConn.use_count() << ")" << std::endl; return *pConn; } void disconnect(connection pConn) { std::cout << "connection close(" << pConn.ip << ":" << pConn.port << ")" << std::endl; } void f(destination& d) { connection conn = connect(&d); std::shared_ptr<connection> p(&conn,[](connection* pConn){disconnect(*pConn);}); std::cout << "connection now(" << p.use_count() << ")" << std::endl; } int main() { destination dest("202.118.176.67",3316); f(dest); return 0; }
ex12_19.h
#ifndef CP5_ex12_19_h #define CP5_ex12_19_h #include <vector> #include <string> #include <initializer_list> #include <memory> #include <exception> using std::vector; using std::string; class StrBlobPtr; class StrBlob { public: using size_type = vector<string>::size_type; friend class StrBlobPtr; StrBlobPtr begin(); StrBlobPtr end(); StrBlob():data(std::make_shared<vector<string>>()) {} StrBlob(std::initializer_list<string> il):data(std::make_shared<vector<string>>(il)){} size_type size() const { return data->size(); } bool empty() const { return data->empty(); } void push_back(const string& t) { data->push_back(t); } void pop_back() { check(0,"pop_back on empty StrBlob"); data->pop_back(); } std::string& back() { check(0, "back on empty StrBlob"); return data->back(); } const std::string& front() const { check(0, "front on empty StrBlob"); return data->front(); } const std::string& back() const { check(0, "back on empty StrBlob"); return data->back(); } private: void check(size_type i,const string& msg) const { if(i>=data->size()) throw std::out_of_range(msg); } private: std::shared_ptr<vector<string>> data; }; class StrBlobPtr { public: StrBlobPtr():curr(0){} StrBlobPtr(StrBlob& a,size_t sz = 0):wptr(a.data),curr(sz){} bool operator!=(const StrBlobPtr& p) { return p.curr!=curr; } string& deref()const { auto p = check(curr,"dereference past end"); return (*p)[curr]; } StrBlobPtr& incr() { check(curr,"increament past end of StrBlobPtr"); ++curr; return *this; } private: std::shared_ptr<vector<string>> check(size_t i,const string& msg) const { auto ret = wptr.lock(); if(!ret) throw std::runtime_error("unbound StrBlobPtr"); if(i>=ret->size()) throw std::out_of_range(msg); return ret; } std::weak_ptr<vector<string>> wptr; size_t curr; }; #endif
#include "ex12_19.h" StrBlobPtr StrBlob::begin() { return StrBlobPtr(*this); } StrBlobPtr StrBlob::end() { return StrBlobPtr(*this,data->size()); }
#include "ex12_19.h" #include <fstream> #include <iostream> int main() { std::ifstream ifs("book.txt"); StrBlob blob; for(std::string str; std::getline(ifs,str);) blob.push_back(str); for(StrBlobPtr pbeg(blob.begin()),pend(blob.end()); pbeg!=pend; pbeg.incr()) std::cout<<pbeg.deref()<<std::endl; }
ex12_22.h
#ifndef CP5_ex12_22_h #define CP5_ex12_22_h #include <vector> #include <string> #include <initializer_list> #include <memory> #include <exception> using std::vector; using std::string; class ConstStrBlobPtr; class StrBlob { public: using size_type = vector<string>::size_type; friend class ConstStrBlobPtr; StrBlobPtr begin() const; StrBlobPtr end() const; StrBlob():data(std::make_shared<vector<string>>()) {} StrBlob(std::initializer_list<string> il):data(std::make_shared<vector<string>>(il)) {} size_type size() const { return data->size(); } bool empty() const { return data->empty(); } void push_back(const string& t) { data->push_back(t); } void pop_back() { check(0,"pop_back on empty StrBlob"); data->pop_back(); } std::string& back() { check(0, "back on empty StrBlob"); return data->back(); } const std::string& front() const { check(0, "front on empty StrBlob"); return data->front(); } const std::string& back() const { check(0, "back on empty StrBlob"); return data->back(); } private: void check(size_type i,const string& msg) const { if(i>=data->size()) throw std::out_of_range(msg); } private: std::shared_ptr<vector<string>> data; }; class ConstStrBlobPtr { public: ConstStrBlobPtr():curr(0) {} ConstStrBlobPtr(const StrBlob& a,size_t sz = 0):wptr(a.data),curr(sz) {} bool operator!=(ConstStrBlobPtr& p) { return p.curr!=curr; } const string& deref()const { auto p = check(curr,"dereference past end"); return (*p)[curr]; } ConstStrBlobPtr& incr() { check(curr,"increament past end of StrBlobPtr"); ++curr; return *this; } private: std::shared_ptr<vector<string>> check(size_t i,const string& msg) const { auto ret = wptr.lock(); if(!ret) throw std::runtime_error("unbound StrBlobPtr"); if(i>=ret->size()) throw std::out_of_range(msg); return ret; } std::weak_ptr<vector<string>> wptr; size_t curr; }; #endif
#include "ex12_19.h" ConstStrBlobPtr StrBlob::begin() const { return ConstStrBlobPtr(*this); } ConstStrBlobPtr StrBlob::end() const { return ConstStrBlobPtr(*this,data->size()); }
#include <iostream> #include <string> #include <cstring> int main() { char *concatenate_string = new char[255](); strcat(concatenate_string,"hello "); strcat(concatenate_string,"world"); std::cout << concatenate_string << std::endl; delete[] concatenate_string; std::string str1{"hello "},str2{"world"}; std::cout << str1+str2 << std::endl; }
#include <iostream> int main() { std::cout << "How long do you want the string? "; int size {0}; std::cin >> size; char* input = new char[size + 1](); std::cin.ignore(); std::cout << "input the string: "; std::cin.get(input, size + 1); std::cout << input; delete[] input; }
#include <iostream> #include <string> #include <memory> void input_reverse_output_string(int n) { std::allocator<std::string> alloc; auto const p = alloc.allocate(n); std::string s; auto q = p; while(std::cin >> s && q!=p+n) alloc.construct(q++,s); while(q!=p) { std::cout << *--q << " "; alloc.destroy(q); } alloc.deallocate(p,n); } int main() { input_reverse_output_string(5); return 0; }
ex12_27_30.h
#ifndef CP5_ex12_27_h #define CP5_ex12_27_h #include <string> using std::string; #include <vector> using std::vector; #include <memory> using std::shared_ptr; #include <iostream> #include <fstream> #include <map> #include <set> class QueryResult; class TextQuery { public: using LineNo = vector<string>::size_type; TextQuery(std::ifstream&); QueryResult query(const string&) const; private: shared_ptr<vector<string>> input; std::map<string, shared_ptr<std::set<LineNo>>> result; }; class QueryResult { public: friend std::ostream& print(std::ostream&, const QueryResult&); public: QueryResult(const string& s, shared_ptr<std::set<TextQuery::LineNo>> set, shared_ptr<vector<string>> v) : word(s), nos(set), input(v) { } private: string word; shared_ptr<std::set<TextQuery::LineNo>> nos; shared_ptr<vector<string>> input; }; std::ostream& print(std::ostream&, const QueryResult&); #endif
#include "ex12_27_30.h" #include <sstream> #include <algorithm> TextQuery::TextQuery(std::ifstream& ifs) : input(new vector<string>) { LineNo lineNo {0}; for (string line; std::getline(ifs, line); ++lineNo) { input->push_back(line); std::istringstream line_stream(line); for (string text, word; line_stream >> text; word.clear()) { std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct); auto& nos = result[word]; if (!nos) nos.reset(new std::set<LineNo>); nos->insert(lineNo); } } } QueryResult TextQuery::query(const string& str) const { static shared_ptr<std::set<LineNo>> nodate(new std::set<LineNo>); auto found = result.find(str); if (found == result.end()) return QueryResult(str, nodate, input); else return QueryResult(str, found->second, input); } std::ostream& print(std::ostream& out, const QueryResult& qr) { out << qr.word << " occurs " << qr.nos->size() << (qr.nos->size() > 1 ? " times" : " time") << std::endl; for (auto i : *qr.nos) out << "\t(line " << i + 1 << ") " << qr.input->at(i) << std::endl; return out; }
#include "ex12_27_30.h" #include <iostream> void runQueries(std::ifstream& infile) { TextQuery tq(infile); while (true) { std::cout << "enter word to look for, or q to quit: "; string s; if (!(std::cin >> s) || s == "q") break; print(std::cout, tq.query(s)) << std::endl; } } int main() { std::ifstream file("<span style="color: rgb(24, 54, 145); font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; line-height: 16px; white-space: pre;">storyDataFile</span>.txt"); runQueries(file); }
#include <string> #include <vector> #include <memory> #include <iostream> #include <fstream> #include <sstream> #include <map> #include <set> #include <algorithm> using std::string; using std::vector; using std::shared_ptr; int main() { std::ifstream file("letter.txt"); vector<string> input; std::map<string, std::set<decltype(input.size())>> dictionary; decltype(input.size()) lineNo {0}; for (string line; std::getline(file, line); ++lineNo) { input.push_back(line); std::istringstream line_stream(line); for (string text, word; line_stream >> text; word.clear()) { std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct); dictionary[word].insert(lineNo); } } while (true) { std::cout << "enter word to look for, or q to quit: "; string s; if (!(std::cin >> s) || s == "q") break; auto found = dictionary.find(s); if (found != dictionary.end()) { std::cout << s << " occurs " << found->second.size() << (found->second.size() > 1 ? " times" : " time") << std::endl; for (auto i : found->second) std::cout << "\t(line " << i + 1 << ") " << input.at(i) << std::endl; } else std::cout << s << " occurs 0 time" << std::endl; } }
ex12_32.h
#ifndef CP5_ex12_32_h #define CP5_ex12_32_h #include "ex12_22.h" using std::shared_ptr; #include <iostream> #include <fstream> #include <map> #include <set> class QueryResult; class TextQuery { public: TextQuery(std::ifstream&); QueryResult query(const string&) const; private: shared_ptr<StrBlob> input; std::map<string, shared_ptr<std::set<StrBlob::size_type>>> result; }; class QueryResult { public: friend std::ostream& print(std::ostream&, const QueryResult&); public: QueryResult(const string& s, shared_ptr<std::set<StrBlob::size_type>> set, shared_ptr<StrBlob> v) : word(s), nos(set), input(v) { } private: string word; shared_ptr<std::set<StrBlob::size_type>> nos; shared_ptr<StrBlob> input; }; std::ostream& print(std::ostream&, const QueryResult&); #endif
#include "ex12_32.h" #include <sstream> #include <algorithm> TextQuery::TextQuery(std::ifstream& ifs) : input(new StrBlob) { StrBlob::size_type lineNo {0}; for (string line; std::getline(ifs, line); ++lineNo) { input->push_back(line); std::istringstream line_stream(line); for (string text, word; line_stream >> text; word.clear()) { std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct); auto& nos = result[word]; if (!nos) nos.reset(new std::set<StrBlob::size_type>); nos->insert(lineNo); } } } QueryResult TextQuery::query(const string& str) const { static shared_ptr<std::set<StrBlob::size_type>> nodate( new std::set<StrBlob::size_type>); auto found = result.find(str); if (found == result.end()) return QueryResult(str, nodate, input); else return QueryResult(str, found->second, input); } std::ostream& print(std::ostream& out, const QueryResult& qr) { out << qr.word << " occurs " << qr.nos->size() << (qr.nos->size() > 1 ? " times" : " time") << std::endl; for (auto i : *qr.nos) { ConstStrBlobPtr p(*qr.input, i); out << "\t(line " << i + 1 << ") " << p.deref() << std::endl; } return out; }
ex12_33.h
#ifndef CP5_ex12_33_h #define CP5_ex12_33_h #include "ex12_22.h" using std::shared_ptr; #include <iostream> #include <fstream> #include <map> #include <set> class QueryResult; class TextQuery { public: TextQuery(std::ifstream&); QueryResult query(const string&) const; private: shared_ptr<StrBlob> input; std::map<string, shared_ptr<std::set<StrBlob::size_type>>> result; }; class QueryResult { public: using ResultIter = std::set<StrBlob::size_type>::iterator; friend std::ostream& print(std::ostream&, const QueryResult&); public: QueryResult(const string& s, shared_ptr<std::set<StrBlob::size_type>> set, shared_ptr<StrBlob> v) : word(s), nos(set), input(v) { } ResultIter begin() const { return nos->begin(); } ResultIter end() const { return nos->end(); } shared_ptr<StrBlob> get_file() const { return input; } private: string word; shared_ptr<std::set<StrBlob::size_type>> nos; shared_ptr<StrBlob> input; }; std::ostream& print(std::ostream&, const QueryResult&); #endif
#include "ex12_33.h" #include <sstream> #include <algorithm> TextQuery::TextQuery(std::ifstream& ifs) : input(new StrBlob) { StrBlob::size_type lineNo {0}; for (string line; std::getline(ifs, line); ++lineNo) { input->push_back(line); std::istringstream line_stream(line); for (string text, word; line_stream >> text; word.clear()) { std::remove_copy_if(text.begin(), text.end(), std::back_inserter(word), ispunct); auto& nos = result[word]; if (!nos) nos.reset(new std::set<StrBlob::size_type>); nos->insert(lineNo); } } } QueryResult TextQuery::query(const string& str) const { static shared_ptr<std::set<StrBlob::size_type>> nodate( new std::set<StrBlob::size_type>); auto found = result.find(str); if (found == result.end()) return QueryResult(str, nodate, input); else return QueryResult(str, found->second, input); } std::ostream& print(std::ostream& out, const QueryResult& qr) { out << qr.word << " occurs " << qr.nos->size() << (qr.nos->size() > 1 ? " times" : " time") << std::endl; for (auto it = qr.begin(); it != qr.end(); ++it) { ConstStrBlobPtr p(*qr.get_file(), *it); out << "\t(line " << *it + 1 << ") " << p.deref() << std::endl; } return out; }
版权声明:本文为博主原创文章,如果转载,请注明出处
《C++primer(第五版)》学习之路-第十二章:动态内存
标签:c++primer
原文地址:http://blog.csdn.net/libin1105/article/details/48751823