1. 程式人生 > >C++Primer第五版 習題答案 第十二章 動態記憶體(Dynamic Memory)

C++Primer第五版 習題答案 第十二章 動態記憶體(Dynamic Memory)

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()