C++ string类的简单实现 (2)

参考

https://coolshell.cn/articles/10478.html#jtss-tsina

分析

如果一个class带有指针类型的数据成员,那么请思考默认的copy ctorcopy assign是否合适。如果你需要深拷贝那么默认的行为就不合适了(默认为浅拷贝)。并且如果你的编译器支持c++11,可以考虑是否可以利用右值引用来提高效率,这时需要实现move ctormove assign(注意nonexcept的使用)。最后,当然别忘了dtor

源码

#include 
#include 
#include 
#include 
#include 
#include 
#include 

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& 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 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

你可能感兴趣的:(C++)