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

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

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

文章目录

      • 练习13.41
      • 练习13.42
      • 练习13.43
      • 练习13.44
      • 练习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 <memory>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<char*, char*> alloc_n_copy(const char*, const char*);void range_initializer(const char*, const char*);void free();private:char *elements;char *end;std::allocator<char> alloc;
};#endif

CPP文件

#include "exercise13_44.h"#include <algorithm>
#include <iostream>std::pair<char*,char*>
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<char*>(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<int> vi(100);
int? r1 = f();
int? r2 = vi[0];
int? r3 = r1;
int? r4 = vi[0] * f();
int f();
vector<int> 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 <memory>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<char*, char*> alloc_n_copy(const char*, const char*);void range_initializer(const char*, const char*);void free();private:char *elements;char *end;std::allocator<char> alloc;
};#endif

CPP文件

#include "exercise13_44.h"#include <algorithm>
#include <iostream>std::pair<char*,char*>
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<char*>(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 <vector>
#include <iostream>// Test reference to http://coolshell.cn/articles/10478.htmlvoid 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<String> 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