C++Primer第五版 習題答案 第十二章 動態記憶體(Dynamic Memory)
阿新 • • 發佈:2018-12-15
12.1
b1包含4個元素; b2被銷燬。
12.2
strblob.h
#ifndef STRBLOB_H_
#define STRBLOB_H_
#include <string>
#include <initializer_list>
#include <memory>
#include <vector>
#include <stdexcept>
class StrBlob
{
public:
typedef std::vector<std::string>::size_type size_type;
StrBlob ();
StrBlob(std::initializer_list<std::string> il);
size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }
void push_back(const std::string &t) { data->push_back(t); }
void pop_back();
std::string& front();
std::string& back();
const std::string& front() const;
const std::string& back() const;
private:
std::shared_ptr<std::vector<std::string>> data;
void check(size_type i, const std::string &msg) const;
};
StrBlob::StrBlob() : data(std::make_shared<std::vector<std::string>>()){}
StrBlob:: StrBlob(std::initializer_list<std::string> il) : data(std::make_shared<std::vector<std::string>>(il)){}
void StrBlob::check(size_type i, const std::string &msg) const
{
if(i >= data->size())
throw std::out_of_range(msg);
}
std::string & StrBlob::front()
{
check(0, "front on empty StrBlob");
return data->front();
}
std::string & StrBlob::back()
{
check(0, "back on empty StrBlob");
return data->back();
}
const std::string& StrBlob::front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
const std::string& StrBlob::back() const
{
check(0, "back on empty StrBlob");
return data->back();
}
void StrBlob::pop_back()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
#endif
ex02.cpp
#include "StrBlob.h"
#include <iostream>
int main()
{
StrBlob b1 = {"a", "an", "the"};
const StrBlob b2 = {"a", "b", "c"};
std::cout << b1.back() << std::endl;
std::cout << b2.back() << std::endl;
return 0;
}
12.03
不需要,新增進去雖然編譯器不會報錯,但是這樣不符合類使用者的使用習慣。
12.04
可以忽略,本身i就是大於0的。
12.05
使用explicit之後 優點:我們可以清楚地知道使用的是哪種型別; 缺點:不易使用,需要顯示地初始化。
12.06
#include <string>
#include <iostream>
#include <vector>
std::vector<int> *create_vi()
{
return new std::vector<int>;
}
void push_vi(std::vector<int> *p)
{
int i;
while(std::cin >> i)
p->push_back(i);
}
void print_vi(std::vector<int> *p)
{
for(const auto i : (*p))
std::cout << i << std::endl;
}
int main()
{
auto p = create_vi();
push_vi(p);
print_vi(p);
delete p;
return 0;
}
12.07
#include <string>
#include <iostream>
#include <vector>
#include <memory>
std::shared_ptr<std::vector<int>> create_vi()
{
return std::make_shared<std::vector<int>>();
}
void push_vi(std::shared_ptr<std::vector<int>> p)
{
int i;
while(std::cin >> i)
p->push_back(i);
}
void print_vi(std::shared_ptr<std::vector<int>> p)
{
for(const auto i : (*p))
std::cout << i << std::endl;
}
int main()
{
auto p = create_vi();
push_vi(p);
print_vi(p);
// delete p;
return 0;
}
12.08
指標p被轉換成bool值,new的記憶體沒有被delete,記憶體沒有被釋放。
12.09
r=q後r所指的記憶體沒有釋放,應該先delete r,再r=q; 第二段程式碼記憶體會自動釋放。
12.10
正確。
12.11
離開process時,p指向的記憶體會被釋放,再使用p指標時會出現錯誤。
12.12
(a)合法,將智慧指標賦值給process; (b)不合法,shared_ptr初始化內建指標時需要使用直接初始化的形式; (c)不合法,shared_ptr初始化內建指標時需要使用直接初始化的形式; (d)合法。
12.13
sp和p指向的是同一個記憶體,釋放了p所指向的記憶體後,再使用sp呼叫物件時可能會出錯。
12.14
#include <string>
#include <memory>
#include <iostream>
struct destination
{
std::string des;
destination(std::string des_) : des(des_){}
};
struct connection
{
std::string conn;
connection(std::string conn_) : conn(conn_){}
};
connection connect(destination *des_)
{
std::cout << "connect to " << des_->des << std::endl;
return connection (des_->des);
}
void disconnect(connection conn_)
{
std::cout << "disconnect " << conn_.conn << std::endl;
}
void end_connection(connection *p){ disconnect(*p); }
void f(destination &d)
{
connection c = connect(&d);
std::shared_ptr<connection> p(&c, end_connection);
std::cout << "connecting now(" << p.use_count() << ")" << std::endl;
}
int main()
{
destination des("aaa");
f(des);
return 0;
}
12.15
#include <string>
#include <memory>
#include <iostream>
struct destination
{
std::string des;
destination(std::string des_) : des(des_){}
};
struct connection
{
std::string conn;
connection(std::string conn_) : conn(conn_){}
};
connection connect(destination *des_)
{
std::cout << "connect to " << des_->des << std::endl;
return connection (des_->des);
}
void disconnect(connection conn_)
{
std::cout << "disconnect " << conn_.conn << std::endl;
}
void end_connection(connection *p){ disconnect(*p); }
void f(destination &d)
{
connection c = connect(&d);
std::shared_ptr<connection> p(&c, [](connection *p){ disconnect(*p); });
std::cout << "connecting now(" << p.use_count() << ")" << std::endl;
}
int main()
{
destination des("aaa");
f(des);
return 0;
}
12.16
#include <memory>
#include <iostream>
int main()
{
std::unique_ptr<int> up1(new int(1));
// std::unique_ptr<int> up2(up1);
// std::unique_ptr<int> up2 = up1;
std::unique_ptr<int> up2;
up2.reset(up1.release());
std::cout << *up2 << std::endl;
return 0;
}
$ g++ -o ex16 ex16.cpp -std=c++11
ex16.cpp: In function ‘int main()’:
ex16.cpp:6:30: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
std::unique_ptr<int> up2(up1);
^
In file included from /usr/include/c++/4.8/memory:81:0,
from ex16.cpp:1:
/usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here
unique_ptr(const unique_ptr&) = delete;
^
12.17
(a)非法,初始化錯誤; (b)編譯時合法,執行時會報錯,因為pi不是new出來的,銷燬時使用預設的delete會出錯; (c)編譯時合法,但是執行時會導致空懸指標,unique_ptr釋放空間時,使用pi2指標會出錯; (d)編譯時合法,執行時會報錯,因為指標不是new出來的,銷燬時使用預設的delete會出錯; (e)合法; (f)編譯時合法,但是會導致兩次delete或者一個delete後另一個變為空懸指標。
12.18
多個shared_ptr可以指向同一個物件,直接賦值即可,無需release成員。
12.19
StrBlob_ex19.h
#ifndef STRBLOB_H_
#define STRBLOB_H_
#include <string>
#include <initializer_list>
#include <memory>
#include <vector>
#include <stdexcept>
class StrBlobPtr;
class StrBlob
{
public:
friend class StrBlobPtr;
typedef std::vector<std::string>::size_type size_type;
StrBlob();
StrBlob(std::initializer_list<std::string> il);
size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }
void push_back(const std::string &t) { data->push_back(t); }
void pop_back();
std::string& front();
std::string& back();
const std::string& front() const;
const std::string& back() const;
StrBlobPtr begin();
StrBlobPtr end();
private:
std::shared_ptr<std::vector<std::string>> data;
void check(size_type i, const std::string &msg) const;
};
class StrBlobPtr
{
public:
StrBlobPtr() : curr(0){};
StrBlobPtr(StrBlob &a, size_t sz = 0) : wptr(a.data), curr(sz) {}
std::string& deref() const;
StrBlobPtr& incr();
private:
std::shared_ptr<std::vector<std::string>> check(std::size_t, const std::string&) const;
std::weak_ptr<std::vector<std::string>> wptr;
std::size_t curr;
};
std::shared_ptr<std::vector<std::string>> StrBlobPtr::check(std::size_t i, const std::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::string& StrBlobPtr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobPtr& StrBlobPtr::incr()
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
StrBlob::StrBlob() : data(std::make_shared<std::vector<std::string>>()){}
StrBlob::StrBlob(std::initializer_list<std::string> il) : data(std::make_shared<std::vector<std::string>>(il)){}
void StrBlob::check(size_type i, const std::string &msg) const
{
if(i >= data->size())
throw std::out_of_range(msg);
}
std::string & StrBlob::front()
{
check(0, "front on empty StrBlob");
return data->front();
}
std::string & StrBlob::back()
{
check(0, "back on empty StrBlob");
return data->back();
}
const std::string& StrBlob::front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
const std::string& StrBlob::back() const
{
check(0, "back on empty StrBlob");
return data->back();
}
void StrBlob::pop_back()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
StrBlobPtr StrBlob::begin() { return StrBlobPtr(*this); }
StrBlobPtr StrBlob::end()
{
auto ret = StrBlobPtr(*this, data->size()