C++ string類的簡單實現 (2)
阿新 • • 發佈:2018-12-25
參考
分析
如果一個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