C++ Primer第五版_第十三章习题答案(41~50)

文章目录

      • 练习13.41
      • 练习13.42
      • 练习13.43
      • 练习13.44
        • 头文件
        • CPP文件
      • 练习13.45
      • 练习13.46
      • 练习13.47
        • 头文件
        • CPP文件
      • 练习13.48
      • 练习13.49
      • 练习13.50

练习13.41

在 push_back 中,我们为什么在 construct 调用中使用后置递增运算?如果使用前置递增运算的话,会发生什么?

会出现 unconstructed

练习13.42

在你的 TextQuery 和 QueryResult 类中用你的 StrVec 类代替vector,以此来测试你的 StrVec 类。

练习13.43

重写 free 成员,用 for_each 和 lambda 来代替 for 循环 destroy 元素。你更倾向于哪种实现,为什么?

重写

for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); });

更倾向于函数式写法。

练习13.44

编写标准库 string 类的简化版本,命名为 String。你的类应该至少有一个默认构造函数和一个接受 C 风格字符串指针参数的构造函数。使用 allocator 为你的 String类分配所需内存。

头文件

#ifndef String_h
#define String_h

#include 

class String
{
public:
	String() :String("") {}
	String(const char *);
	String(const String&);
	String& operator=(const String&);
	~String();

	const char* c_str() const { return elements; }
	size_t size() const { return end - elements; }
	size_t length() const { return end - elements + 1; }

private:
	std::pair alloc_n_copy(const char*, const char*);
	void range_initializer(const char*, const char*);
	void free();

private:
	char *elements;
	char *end;
	std::allocator alloc;
};

#endif

CPP文件

#include "exercise13_44.h"

#include 
#include 

std::pair
String::alloc_n_copy(const char* b, const char* e)
{
	auto str = alloc.allocate(e - b);
	return{ str, std::uninitialized_copy(b, e, str) };
}

void String::range_initializer(const char* first, const char* last)
{
	auto newstr = alloc_n_copy(first, last);
	elements = newstr.first;
	end = newstr.second;
}

String::String(const char* s)
{
	char *s1 = const_cast(s);
	while (*s1)
	{
		++s1;
	}
	range_initializer(s, ++s1);
}

String::String(const String& rhs)
{
	range_initializer(rhs.elements, rhs.end);
	std::cout << "copy constructor" << std::endl;
}

void String::free()
{
	if (elements)
	{
		std::for_each(elements, end, [this](char &c) { alloc.destroy(&c); });
		alloc.deallocate(elements, end - elements);
	}
}

String::~String()
{
	free();
}

String& String::operator=(const String& rhs)
{
	auto newstr = alloc_n_copy(rhs.elements, rhs.end);
	free();
	elements = newstr.first;
	end = newstr.second;
	std::cout << "copy-assignment" << std::endl;
	return *this;
}

练习13.45

解释左值引用和右值引用的区别?

定义:

  • 常规引用被称为左值引用
  • 绑定到右值的引用被称为右值引用。

练习13.46

什么类型的引用可以绑定到下面的初始化器上?

int f();
vector vi(100);
int? r1 = f();
int? r2 = vi[0];
int? r3 = r1;
int? r4 = vi[0] * f();
int f();
vector vi(100);
int&& r1 = f();
int& r2 = vi[0];
int& r3 = r1;
int&& r4 = vi[0] * f();

练习13.47

对你在练习13.44中定义的 String类,为它的拷贝构造函数和拷贝赋值运算符添加一条语句,在每次函数执行时打印一条信息。

头文件

#ifndef String_h
#define String_h

#include 

class String
{
public:
	String() :String("") {}
	String(const char *);
	String(const String&);
	String& operator=(const String&);
	~String();

	const char* c_str() const { return elements; }
	size_t size() const { return end - elements; }
	size_t length() const { return end - elements + 1; }

private:
	std::pair alloc_n_copy(const char*, const char*);
	void range_initializer(const char*, const char*);
	void free();

private:
	char *elements;
	char *end;
	std::allocator alloc;
};

#endif

CPP文件

#include "exercise13_44.h"

#include 
#include 

std::pair
String::alloc_n_copy(const char* b, const char* e)
{
	auto str = alloc.allocate(e - b);
	return{ str, std::uninitialized_copy(b, e, str) };
}

void String::range_initializer(const char* first, const char* last)
{
	auto newstr = alloc_n_copy(first, last);
	elements = newstr.first;
	end = newstr.second;
}

String::String(const char* s)
{
	char *s1 = const_cast(s);
	while (*s1)
	{
		++s1;
	}
	range_initializer(s, ++s1);
}

String::String(const String& rhs)
{
	range_initializer(rhs.elements, rhs.end);
	std::cout << "copy constructor" << std::endl;
}

void String::free()
{
	if (elements)
	{
		std::for_each(elements, end, [this](char &c) { alloc.destroy(&c); });
		alloc.deallocate(elements, end - elements);
	}
}

String::~String()
{
	free();
}

String& String::operator=(const String& rhs)
{
	auto newstr = alloc_n_copy(rhs.elements, rhs.end);
	free();
	elements = newstr.first;
	end = newstr.second;
	std::cout << "copy-assignment" << std::endl;
	return *this;
}

练习13.48

定义一个vector 并在其上多次调用 push_back。运行你的程序,并观察 String 被拷贝了多少次。

#include "exercise13_44.h"
#include 
#include 

// Test reference to http://coolshell.cn/articles/10478.html

void foo(String x)
{
	std::cout << x.c_str() << std::endl;
}

void bar(const String& x)
{
	std::cout << x.c_str() << std::endl;
}

String baz()
{
	String ret("world");
	return ret;
}

int main()
{
	char text[] = "world";

	String s0;
	String s1("hello");
	String s2(s0);
	String s3 = s1;
	String s4(text);
	s2 = s1;

	foo(s1);
	bar(s1);
	foo("temporary");
	bar("temporary");
	String s5 = baz();

	std::vector svec;
	svec.reserve(8);
	svec.push_back(s0);
	svec.push_back(s1);
	svec.push_back(s2);
	svec.push_back(s3);
	svec.push_back(s4);
	svec.push_back(s5);
	svec.push_back(baz());
	svec.push_back("good job");

	for (const auto &s : svec)
	{
		std::cout << s.c_str() << std::endl;
	}
}

练习13.49

为你的 StrVec、String 和 Message 类添加一个移动构造函数和一个移动赋值运算符。

练习13.50

在你的 String 类的移动操作中添加打印语句,并重新运行13.6.1节的练习13.48中的程序,它使用了一个vector,观察什么时候会避免拷贝。

String baz()
{
    String ret("world");
    return ret; 	// first avoided
}

String s5 = baz();  // second avoided

你可能感兴趣的:(C++《i+1》,c++)