参考
分析
如果一个class带有指针类型的数据成员,那么请思考默认的copy ctor
和copy assign
是否合适。如果你需要深拷贝
那么默认的行为就不合适了(默认为浅拷贝)。并且如果你的编译器支持c++11,可以考虑是否可以利用右值引用
来提高效率,这时需要实现move ctor
和move assign
(注意nonexcept的使用)。最后,当然别忘了dtor
。
源码
#include <stdint.h>
#include <stdio.h>
#include <utility>
#include <string.h>
#include <malloc.h>
#include <iostream>
#include <vector>
class String {
public:
// ctor
String() : data_(new char[1])
{
std::cout << "default ctor this:" << std::hex << this << std::endl;
data_[0] = '\0';
}
String(const char* str) : data_(new char[strlen(str) + 1])
{
std::cout << "ctor witch const char* this:" << std::hex << this << std::endl;
data_[0] = '\0';
strcpy(data_, str);
}
// copy ctor
String(const String& rhs) noexcept : data_(new char[strlen(rhs.data_) + 1])
{
std::cout << "copy ctor this:" << std::hex << this
<< " rhs: " << std::hex << &rhs
<< std::endl;
strcpy(data_, rhs.data_);
}
// copy assign
String& operator= (const String& rhs) {
String tmp(rhs);
swap(tmp);
return *this;
}
/*
String& operator= (String rhs)
{
std::cout << "copy assign this:" << std::hex << this
<< " rhs: " << std::hex << &rhs
<< std::endl;
swap(rhs);
return *this;
}
//注意:
//String s("hello");
//s = "world"; 会提示和move copy assign ambiguous
*/
// move ctor
String(String&& rhs) noexcept : data_(rhs.data_)
{
std::cout << "move ctor this:" << std::hex << this
<< " rhs: " << std::hex << &rhs
<< std::endl;
rhs.data_ = nullptr;
}
// move assign
String& operator= (String&& rhs)
{
std::cout << "move assign this:" << std::hex << this
<< " rhs: " << std::hex << &rhs
<< std::endl;
swap(rhs);
return *this;
}
// dtor
~String()
{
std::cout << "dtor " << std::hex << this << std::endl;
delete [] data_;
}
// swap
void swap(String& rhs)
{
std::cout << "member swap this:" << std::hex << this
<< " rhs: " << std::hex << &rhs
<< std::endl;
using std::swap;
swap(data_, rhs.data_);
}
const char* c_str() const { return data_; }
private:
char* data_;
};
void swap(String& lhs, String& rhs) {
std::cout << "non-member swap" << std::endl;
lhs.swap(rhs);
}
namespace std {
template<>
void swap<String>(String& lhs, String& rhs) {
std::cout << "std::swap total template specialization" << std::endl;
lhs.swap(rhs);
}
}
std::ostream& operator<< (std::ostream& os, const String& s)
{
os << s.c_str();
return os;
}
注意上面的class根据Effective C++ rule 25,实现了member-swap, non-member-swap以及std::swap的全特化版本。
在vector中使用
String s0;
String s1("hello");
std::vector<String> svec;
//svec.reserve(4); // 打开此行分析有什么变化
//svec.resize(4);
std::cout << "size: "<< svec.size() << " cap:"<< svec.capacity() << std::endl;
svec.push_back(s0);
std::cout << "size: "<< svec.size() << " cap:"<< svec.capacity() << std::endl;
svec.push_back(s1);
std::cout << "size: "<< svec.size() << " cap:"<< svec.capacity() << std::endl;
svec.push_back(baz());
std::cout << "size: "<< svec.size() << " cap:"<< svec.capacity() << std::endl;
svec.push_back("good job");
std::cout << "size: "<< svec.size() << " cap:"<< svec.capacity() << std::endl;
return 0;
右值引用 和 nonexcept
move ctor
在标明nonexcept
时,才会被vector使用(在需要reallocation时),否则会使用copy ctor