在 push_back 中,我们为什么在 construct 调用中使用后置递增运算?如果使用前置递增运算的话,会发生什么?
会出现 unconstructed
。
在你的 TextQuery 和 QueryResult 类中用你的 StrVec 类代替vector,以此来测试你的 StrVec 类。
重写 free 成员,用 for_each 和 lambda 来代替 for 循环 destroy 元素。你更倾向于哪种实现,为什么?
重写:
for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); });
更倾向于函数式写法。
编写标准库 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
#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;
}
解释左值引用和右值引用的区别?
定义:
什么类型的引用可以绑定到下面的初始化器上?
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.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
#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;
}
定义一个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;
}
}
为你的 StrVec、String 和 Message 类添加一个移动构造函数和一个移动赋值运算符。
在你的 String 类的移动操作中添加打印语句,并重新运行13.6.1节的练习13.48中的程序,它使用了一个vector,观察什么时候会避免拷贝。
String baz()
{
String ret("world");
return ret; // first avoided
}
String s5 = baz(); // second avoided