C++ - Object passing and allocations

  • Example
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
 
#pragma warning(disable: 4996)
 
class String {
    char * p;
public:
    String(const char *s) {
        std::cout << __FUNCSIG__ << std::endl;
        p = strdup(s);
    }
 
    String(const String & other) {
        std::cout << __FUNCSIG__ << std::endl;
        p = strdup(other.p);
    }
 
    ~String() {
        std::cout << __FUNCSIG__ << std::endl;
        free(p);
    }
 
    String & operator = (const String & other) = delete;
};
 
String f1() {
    return String("Hello");
}
 
String f2() {
    auto s = String("Hello");
    return s;
}
 
int main(void)
{
    {
        std::cout << "--- s1 ---" << std::endl;
        auto s1 = f1();
    }
    {
        std::cout << "--- s2 ---" << std::endl;
        auto s2 = f2();
    }
}
  • Output
--- s1 ---
__thiscall String::String(const char *)
__thiscall String::~String(void)
--- s2 ---
__thiscall String::String(const char *)
__thiscall String::String(const class String &)
__thiscall String::~String(void)
__thiscall String::~String(void)
  • Tip
可以发现,对于存在中间变量赋值的返回,会多一次拷贝构造,而直接return是没有额外的开销的。与C#/JAVA不一样(对象为引用的方式传递),而给C++对象赋值就会产生一次拷贝构造,像上面String的例子所示,拷贝构造中可能会涉及到更多的内存分配操作,所以为了减少对象的分配就发展出了`智能指针`的东西,所谓智能指针就是把对象进行包装,同时增加了一个引用计数,当引用计数为0的时候销毁。
改进 C++ 标准类: 对于一个类涉及动态内存或者大量静态内存的时候,我们可以通过在内部使用智能指针管理内存,而无需考虑拷贝构造的开销,因为剩余的部分只是类成员的值与指针的传递复制。
  • 定义智能指针 RefPtr
template <typename T> class RefPtr
{
private:
    T * _ptr;
    int * _ref_count;
    bool _is_array;

    void release()
    {
        if (--(*_ref_count) == 0) {
            if (_ptr != nullptr) {
                if (_is_array) {
                    delete[] _ptr;
                }
                else {
                    delete _ptr;
                }
            }
            delete _ref_count;
        }
    }

    void assign(const RefPtr & other)
    {
        _ptr = other._ptr;
        _ref_count = other._ref_count;
        _is_array = other._is_array;
        (*_ref_count)++;
    }

public:
    RefPtr() : RefPtr(nullptr, false)
    {
    }

    RefPtr(T * ptr, bool is_array = false)
    {
        _ptr = ptr;
        _ref_count = new int(1);
        _is_array = is_array;
    }

    RefPtr(const RefPtr & other)
    {
        assign(other);
    }

    ~RefPtr()
    {
        release();
    }

    RefPtr & operator = (const RefPtr & other)
    {
        release();
        assign(other);
        return *this;
    }

    T * operator ->()
    {
        return _ptr;
    }

    const T * operator ->() const
    {
        return _ptr;
    }

    T * ptr()
    {
        return _ptr;
    }

    const T * ptr() const
    {
        return _ptr;
    }

    int ref_count()
    {
        return *_ref_count;
    }
};
  • 定义内存
template<typename T> class Memory
{
protected:
    T * _ptr;
    int _size;

    Memory<T> & operator =(const Memory<T> &other) = delete;

public:
    Memory()
    {
        _ptr = nullptr;
        _size = 0;
    }

    Memory(T * ptr, int size)
    {
        _ptr = ptr;
        _size = size;
    }

    T * ptr()
    {
        return _ptr;
    }

    const T * ptr() const
    {
        return _ptr;
    }

    int size() const
    {
        return _size;
    }

    void copy(const T * source, int count)
    {
        copy(_ptr, source, count > _size ? _size : count);
    }

    void copy(const Memory<T> & other)
    {
        copy(other.ptr(), other.size());
    }

    static void copy(T * dest, const T * source, int count)
    {
        for (auto i = 0; i < count; i++) {
            dest[i] = source[i];
        }
    }
};
      
template<typename T> class AutoMemory : public Memory<T>
{
private:
    AutoMemory<T> & operator =(const AutoMemory<T> &other) = delete;

public:
    AutoMemory() : AutoMemory(0)
    {
    }

    AutoMemory(int size)
    {
        if (size < 0) {
            throw ArgumentError();
        }
        else {
            this->_size = size;
            this->_ptr = (T *)calloc(this->_size, sizeof(T));
        }
    }

    ~AutoMemory()
    {
        free(this->_ptr);
    }

    void resize(int size)
    {
        this->_size = size;
        this->_ptr = (T *)realloc(this->_ptr, this->_size * sizeof(T));
    }

    AutoMemory<T> dup()
    {
        AutoMemory<T> mem(this->size());
        mem.copy(*this);
        return mem;
    }
};
      
  • 定义 StringBuffer
class StringBuffer : public Buffer<char>
{
private:
    typedef Buffer<char> CharBuffer;

public:
    StringBuffer(int size = 0);
    StringBuffer(const char * s);
    StringBuffer(const char * s, int length);
    void expand(int new_size);
    void copy(const char *s);
    void copy(const char *s, int length);
    void copy(const StringBuffer & other);
    void concat(const char * s);
    void concat(const StringBuffer & other);
    int length() const;
    StringBuffer dup();
    const char * str() const;
    char & operator [](int index);
    char operator [](int index) const;
};
StringBuffer::StringBuffer(int size)
    : CharBuffer(size)
{
    fill(0);
}

StringBuffer::StringBuffer(const char * s)
    : CharBuffer(strlen(s) + 1)
{
    copy(s);
}

StringBuffer::StringBuffer(const char * s, int length)
    : CharBuffer(length + 1)
{
    copy(s, length);
}

void StringBuffer::expand(int new_size)
{
    if (size() < new_size) {
        auto sz = size();
        resize(new_size);
        fill(sz, new_size - sz, 0);
    }
}

void StringBuffer::copy(const char *s)
{
    expand(strlen(s) + 1);
    strcpy(ptr(), s);
}

void StringBuffer::copy(const char *s, int length)
{
    expand(length + 1);
    strncpy(ptr(), s, length);
    ptr()[length] = '\0';
}

void StringBuffer::copy(const StringBuffer & other)
{
    copy(other.str());
}

int StringBuffer::length() const
{
    return strlen(ptr());
}

void StringBuffer::concat(const char * s)
{
    expand(length() + strlen(s) + 1);
    strcat(ptr(), s);
}

void StringBuffer::concat(const StringBuffer & other)
{
    concat(other.str());
}

StringBuffer StringBuffer::dup()
{
    StringBuffer buf(size());
    buf.copy(*this);
    return buf;
}

const char * StringBuffer::str() const
{
    return ptr();
}

char & StringBuffer::operator [](int index)
{
    return at(index);
}

char StringBuffer::operator [](int index) const
{
    return at(index);
}
  • 定义 String
class String
{
private:
    StringBuffer _buf;
    void setbuf(StringBuffer buf);

public:
    String();
    String(const char * source);
    String(const char * source, int count);
    String(const String & other);
    String(StringBuffer & buf);
    ~String();
    Array<char> chars() const;
    int length() const;
    char at(int index) const;
    const char * c_str() const;
    String slice(int index, int count);
    String downcase();
    String upcase();
    String ltrim(const char * blanks = nullptr);
    String rtrim(const char * blanks = nullptr);
    String trim(const char * blanks = nullptr);
    String operator +(const String & other);
    String operator +(const char * other);
    String & operator = (const char * other);
    String & operator = (const String & other);
    bool operator ==(const String & other);
    bool operator >(const String & other);
    bool operator <(const String & other);
    bool operator >=(const String & other);
    bool operator <=(const String & other);

public:
    static String format(const char *fmt, ...);
};
      
String::String()
{
    setbuf(StringBuffer(""));
}

String::String(const char * source)
{
    if (source == nullptr) {
        throw ArgumentError();
    }
    else {
        setbuf(StringBuffer(source));
    }
}

String::String(const char * source, int count)
{
    if (source == nullptr || count < 0) {
        throw ArgumentError();
    }
    else {
        _buf.copy(source, count);
    }
}

String::String(const String & other)
{
    setbuf(other._buf);
}

String::String(StringBuffer & buf)
{
    setbuf(buf);
}

String::~String()
{
}

void String::setbuf(StringBuffer buf)
{
    _buf = buf;
}

Array<char> String::chars() const
{
    return Array<char>(_buf.ptr(), _buf.length());
}

int String::length() const
{
    return _buf.length();
}

char String::at(int index) const
{
    if (index < 0 || index >= length()) {
        throw IndexError();
    }
    else {
        return _buf[index];
    }
}

const char * String::c_str() const
{
    return _buf.str();
}

String String::slice(int index, int count)
{
    if (index < 0 || index >= length()) {
        throw IndexError();
    }
    else {
        return String(_buf.str() + index, count);
    }
}

String String::operator +(const String & other)
{
    auto size = this->length() + other.length();
    auto buf = StringBuffer(size + 1);
    buf.copy(this->_buf);
    buf.concat(other._buf);
    return String(buf);
}

String String::operator +(const char * other)
{
    return *this + String(other);
}

String String::downcase()
{
    auto sb = _buf.dup();
    for (auto i = 0; i < sb.length(); i++) {
        sb[i] = tolower(sb[i]);
    }
    return String(sb);
}

String String::upcase()
{
    auto sb = _buf.dup();
    for (auto i = 0; i < sb.length(); i++) {
        sb[i] = toupper(sb[i]);
    }
    return String(sb);
}

String String::ltrim(const char * blanks)
{
    const char * DEFAULT_BLANK_CHARS = "\r\n\t\v\f ";
    blanks = blanks == nullptr ? DEFAULT_BLANK_CHARS : blanks;
    for (auto i = 0; i < this->length(); i++) {
        if (strchr(blanks, this->at(i)) == nullptr) {
            return String(_buf.str() + i);
        }
    }
    return *this;
}

String String::rtrim(const char * blanks)
{
    const char * DEFAULT_BLANK_CHARS = "\r\n\t\v\f ";
    blanks = blanks == nullptr ? DEFAULT_BLANK_CHARS : blanks;
    for (auto i = length(); i > 0; i--) {
        if (strchr(blanks, this->at(i-1)) == nullptr) {
            return String(_buf.str(), i);
        }
    }
    return *this;
}

String String::trim(const char * blanks)
{
    return ltrim(blanks).rtrim(blanks);
}

String & String::operator =(const char * s)
{
    _buf = String(s)._buf;
    return *this;
}

String & String::operator =(const String & s)
{
    _buf = s._buf;
    return *this;
}

bool String::operator ==(const String & other)
{
    return strcmp(_buf.str(), other._buf.str()) == 0;
}

bool String::operator >(const String & other)
{
    return strcmp(_buf.str(), other._buf.str()) > 0;
}

bool String::operator <(const String & other)
{
    return strcmp(_buf.str(), other._buf.str()) < 0;
}

bool String::operator >=(const String & other)
{
    return strcmp(_buf.str(), other._buf.str()) >= 0;
}

bool String::operator <=(const String & other)
{
    return strcmp(_buf.str(), other._buf.str()) <= 0;
}

String String::format(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    auto size = vsnprintf(nullptr, 0, fmt, args) + 1;
    auto buf = StringBuffer(size);
    vsnprintf(buf.ptr(), size, fmt, args);
    va_end(args);
    return String(buf);
}