I wrote a simple String class implementation using unique_ptr and move semantics. Is my implementation good enough in terms of design and efficiency?
Stringy.h
#pragma once
#include <iostream>
#include <cstring>
#include <memory>
class Stringy {
private:
std::unique_ptr<char[]> p;
std::size_t size;
std::size_t len;
enum {Factor = 3};
static void _debug(const char *x)
{
#if DEBUG
std::cout << "=> " << x << " <=" << std::endl;
#endif
}
public:
Stringy(const char* ptr);
Stringy(const Stringy& Other);
Stringy(Stringy&& Other);
const Stringy& operator=(Stringy Other);
const Stringy& operator=(Stringy&& Other);
void swap(Stringy& Other);
void concat(const Stringy& Other);
void concat(const char* One);
void move(Stringy& Other);
std::size_t length() const;
Stringy operator+(const Stringy& Other) const;
Stringy operator+(const char* ptr) const;
const char& operator[](std::size_t index) const;
char& operator[](std::size_t index);
friend Stringy&& operator+ (Stringy&& Lhs, const char* Rhs);
friend Stringy&& operator+ (Stringy&& Lhs, const Stringy& Rhs);
friend std::ostream& operator<< (std::ostream& cout, const Stringy& Other);
~Stringy();
};
Stringy.cpp
#define DEBUG false
Stringy::Stringy(const char *ptr)
{
_debug("default pointer Ctor");
len = strlen(ptr);
size = len * Factor;
p = std::make_unique<char[]>(size);
std::copy(ptr, ptr + len, p.get());
p[len] = '\0';
}
Stringy::Stringy(const Stringy &Other): size(Other.size), len(0)
{
_debug("Copy Ctor");
p = std::make_unique<char[]>(size);
concat(Other);
}
Stringy::Stringy(Stringy &&Other)
{
_debug("Move Ctor");
move(Other);
}
const Stringy& Stringy::operator=(Stringy Other)
{
_debug("opterator= copy and swap");
swap(Other);
return *this;
}
const Stringy& Stringy::operator=(Stringy &&Other)
{
_debug("Move operator=");
move(Other);
return *this;
}
void Stringy::swap(Stringy &Other)
{
std::swap(size, Other.size);
std::swap(len, Other.len);
std::swap(p, Other.p);
}
//TODO: Reallocate memory if required
void Stringy::concat(const Stringy &Other)
{
std::copy(Other.p.get(), Other.p.get() + Other.len, p.get() + len);
len += Other.len;
p[len] = '\0';
}
//TODO: Reallocate memory if required
void Stringy::concat(const char *One)
{
std::size_t _len = strlen(One);
std::copy(One, One + _len, p.get() + len);
len += _len;
p[len] = '\0';
}
void Stringy::move(Stringy &Other)
{
size = Other.size;
Other.size = 0;
len = Other.len;
Other.len = 0;
p = std::move(Other.p);
Other.p = NULL;
}
std::size_t Stringy::length() const
{
return len;
}
Stringy Stringy::operator+(const Stringy &Other) const
{
_debug("operator+ Other");
Stringy temp(*this);
temp.concat(Other);
return temp;
}
Stringy Stringy::operator+(const char *ptr) const
{
_debug("operator+ ptr");
Stringy temp(*this);
temp.concat(ptr);
return temp;
}
const char& Stringy::operator[](std::size_t index) const
{
return this->p[index];
}
char& Stringy::operator[](std::size_t index)
{
return this->p[index];
}
Stringy::~Stringy()
{
_debug("Dtor");
}
Stringy&& operator+(Stringy &&Lhs, const char *Rhs)
{
Stringy::_debug("operator+ move ptr");
Lhs.concat(Rhs);
return std::move(Lhs);
}
Stringy&& operator+(Stringy &&Lhs, const Stringy &Rhs)
{
Stringy::_debug("operator+ move Other");
Lhs.concat(Rhs);
return std::move(Lhs);
}
std::ostream &operator<<(std::ostream &stream, const Stringy &Other)
{
stream << Other.p.get();
return stream;
}
I benchmarked the class against std::string on QuickBench and it shows 2.5x worse performance, but that's because gcc now uses SSO. With large string size, my class performed comparably to std::string although I would agree they are little biased.
main.cpp
#include <iostream>
#include "Stringy.h"
void custom() {
Stringy firstName = "Sumit";
Stringy lastName = "Dhingra";
Stringy fullName = firstName + "-" + ">" + lastName;
std::cout << fullName << std::endl;
}
void default_() {
std::string firstName = "Sumit";
std::string lastName = "Dhingra";
std::string fullName = firstName + "-" + ">" + lastName;
std::cout << fullName << std::endl;
}
int main() {
#ifdef DEFAULT
default_();
#else
custom();
#endif
}
stringy.cppis obviously incomplete. \$\endgroup\$