c++ string implementation. providing support for range-for loop, iterators, exponential capacity increase,...












1














This is my implementation of string class similar to std::string and supports the following :
a range-for loops,
b iterators,
c basic utility functions,
d exponential capacity increase,
e operator overloads



I am looking for specific reviews on implementation of iterators, exponential capacity increase, usage of noexcept and implementations of some functions like : resize(), operator+=, operator=, operator +



Thanks in advance for any inputs.



mystring.h



#ifndef MY_STRING_H_
#define MY_STRING_H_

#include <cstring>
#include <iostream>
#include <memory>
#include <algorithm>
#include <stdexcept>
#include <limits>

namespace kapil {
class string final {
private:
// default capacity of empty string.
static constexpr size_t default_capacity_ = 16;
// current capacity of the string container.
size_t current_capacity_;
//size of string.
size_t sz_;
// pointer to character
std::unique_ptr<char> ptr_;
public:
string();
string(const string&);
string(string&&) noexcept;
string(const char*);
explicit string(char);
~string() noexcept;

size_t capacity() const noexcept;
size_t size() const noexcept;
size_t length() const noexcept;
void resize(size_t, char ch = '');
void clear() noexcept;
bool empty() const noexcept;
char& at(size_t);
const char& at(size_t) const;
char& back();
const char& back() const;
char& front();
const char& front() const;
string& append(const string&);
string& append(const char*);
string& append(string&&);
string& append(char);
void push_back(char);
string& assign(const string&);
string& assign(const char*);
string& assign(string&&);
void swap(string&);
const char* c_str() const noexcept;
const char* data() const noexcept;



string& operator = (const string&);
string& operator = (string&&) noexcept;
string& operator = (const char*);
string& operator = (char);
string& operator += (const string&);
string& operator += (const char*);
string& operator += (char);
string& operator += (string&&);
char& operator (size_t);
const char& operator (size_t) const;

friend std::ostream& operator << (std::ostream&, const string&);
friend string operator + (const string&, const string&);
friend string operator + (const string&, const char*);
friend string operator + (const char*, const string&);
friend string operator + (string&&, string&&);
friend string operator + (string&&, const char*);
friend string operator + (const char*, string&&);
friend string operator + (const string&, string&&);
friend string operator + (string&&, const string&);
friend string operator + (const string&, char);
friend string operator + (char, const string&);
friend string operator + (string&&, char);
friend string operator + (char, string&&);
friend bool operator == (const string&, const string&) noexcept;
friend bool operator == (const string&, const char*) noexcept;
friend bool operator == (const char*, const string&) noexcept;
friend bool operator == (const string&, char) noexcept;
friend bool operator == (char, const string&) noexcept;
friend bool operator == (const string&, string&&) noexcept;
friend bool operator == (string&&, const string&) noexcept;
friend bool operator == (string&&, string&&) noexcept;
friend bool operator == (string&&, char) noexcept;
friend bool operator == (char, string&&) noexcept;
friend bool operator == (const char*, string&&) noexcept;
friend bool operator == (string&&, const char*) noexcept;
friend bool operator != (const string&, const string&) noexcept;
friend bool operator != (const string&, const char*) noexcept;
friend bool operator != (const char*, const string&) noexcept;
friend bool operator != (const string&, char) noexcept;
friend bool operator != (char, const string&) noexcept;
friend bool operator != (const string&, string&&) noexcept;
friend bool operator != (string&&, const string&) noexcept;
friend bool operator != (string&&, string&&) noexcept;
friend bool operator != (string&&, char) noexcept;
friend bool operator != (char, string&&) noexcept;
friend bool operator != (const char*, string&&) noexcept;
friend bool operator != (string&&, const char*) noexcept;

class iterator
{
private:
string* str_;
size_t index_;
public:
iterator(string* = nullptr, size_t = 0) noexcept;
iterator(const iterator&) noexcept;
iterator(iterator&&) noexcept;
~iterator() noexcept;

iterator& operator = (const iterator&) noexcept;
iterator& operator = (iterator&&) noexcept;
bool operator != (const iterator&) const noexcept;
bool operator == (const iterator&) const noexcept;
iterator& operator ++ () noexcept;
iterator& operator ++ (int) noexcept;
iterator& operator -- () noexcept;
iterator& operator -- (int) noexcept;
char& operator * () const;
};

iterator begin();
iterator end();

class const_iterator
{
private:
const string* str_;
size_t index_;
public:
const_iterator(const string*, size_t) noexcept;
const_iterator(const const_iterator&) noexcept;
const_iterator(const_iterator&&) noexcept;
~const_iterator() noexcept;

const_iterator& operator = (const const_iterator&) noexcept;
const_iterator& operator = (const_iterator&&) noexcept;
bool operator != (const const_iterator&) const noexcept;
bool operator == (const const_iterator&) const noexcept;
const_iterator& operator ++ () noexcept;
const_iterator& operator ++ (int) noexcept;
const_iterator& operator -- () noexcept;
const_iterator& operator -- (int) noexcept;
const char& operator * () const;
};

const_iterator cbegin();
const_iterator cend();

class reverse_iterator
{
private:
string* str_;
size_t index_;
public:
reverse_iterator(string* = nullptr, size_t = 0) noexcept;
reverse_iterator(const reverse_iterator&) noexcept;
reverse_iterator(reverse_iterator&&) noexcept;
~reverse_iterator() noexcept;

reverse_iterator& operator = (const reverse_iterator&) noexcept;
reverse_iterator& operator = (reverse_iterator&&) noexcept;
bool operator != (const reverse_iterator&) const noexcept;
bool operator == (const reverse_iterator&) const noexcept;
reverse_iterator& operator ++ () noexcept;
reverse_iterator& operator ++ (int) noexcept;
reverse_iterator& operator -- () noexcept;
reverse_iterator& operator -- (int) noexcept;
char& operator * () const;
};

reverse_iterator rbegin();
reverse_iterator rend();

class reverse_const_iterator
{
private:
const string* str_;
size_t index_;
public:
reverse_const_iterator(const string*, size_t) noexcept;
reverse_const_iterator(const reverse_const_iterator&) noexcept;
reverse_const_iterator(reverse_const_iterator&&) noexcept;
~reverse_const_iterator() noexcept;

reverse_const_iterator& operator = (const reverse_const_iterator&) noexcept;
reverse_const_iterator& operator = (reverse_const_iterator&&) noexcept;
bool operator != (const reverse_const_iterator&) const noexcept;
bool operator == (const reverse_const_iterator&) const noexcept;
reverse_const_iterator& operator ++ () noexcept;
reverse_const_iterator& operator ++ (int) noexcept;
reverse_const_iterator& operator -- () noexcept;
reverse_const_iterator& operator -- (int) noexcept;
const char& operator * () const;
};

reverse_const_iterator crbegin();
reverse_const_iterator crend();
};
} //kapil

#endif


my_string.cpp



#include "my_string.h"

namespace kapil {
/*
For the given new_string_length, the appropriate capacity is the
next power of 2 that is greater than new_string_length.
*/
size_t get_appropriate_capacity(size_t new_string_length) {
size_t appropriate_capacity = 16;
if ((static_cast<unsigned long>(new_string_length) << 1) > std::numeric_limits<size_t>::max()) {
appropriate_capacity = new_string_length;
} else {
appropriate_capacity = 16;
if (appropriate_capacity <= new_string_length) {
if (!(new_string_length & (new_string_length - 1))) {
appropriate_capacity = new_string_length << 1;
} else {
while (appropriate_capacity < new_string_length) {
appropriate_capacity <<= 1;
}
}
}
}
return appropriate_capacity;
}

/**************************************** member functions *********************/

string::string()
: current_capacity_{ default_capacity_ } {
sz_ = 0;
ptr_ = std::make_unique<char>(current_capacity_ + 1);
ptr_.get()[0] = '';
}

string::string(const string& other) {
current_capacity_ = other.current_capacity_;
sz_ = other.sz_;
ptr_ = std::make_unique<char>(current_capacity_ + 1);
std::strcpy(ptr_.get(), other.ptr_.get());
}

string::string(string&& rval) noexcept
: current_capacity_{ rval.current_capacity_ },
sz_{ rval.sz_ },
ptr_{ std::move(rval.ptr_) } {
}

string::string(const char* c_string) {
sz_ = std::strlen(c_string);
current_capacity_ = get_appropriate_capacity(sz_);
ptr_ = std::make_unique<char>(current_capacity_ + 1);
std::strcpy(ptr_.get(), c_string);
}

string::string(char ch) {
sz_ = 1;
current_capacity_ = default_capacity_;
ptr_ = std::make_unique<char>(current_capacity_ + 1);
ptr_.get()[0] = ch;
ptr_.get()[1] = '';
}

string::~string() noexcept {
current_capacity_ = 0;
sz_ = 0;
ptr_.reset(nullptr);
};


/**************************************** member functions *********************/

size_t string::capacity() const noexcept {
return current_capacity_;
}

size_t string::size() const noexcept {
return sz_;
}

size_t string::length() const noexcept {
return sz_;
}

void string::resize(size_t n, char ch) {
if (n == sz_) {
return;
}

size_t appropriate_capacity = get_appropriate_capacity(n);

std::unique_ptr<char> temp;
auto resized = bool{false};

if (current_capacity_ != appropriate_capacity) {
resized = true;
current_capacity_ = appropriate_capacity;
temp = std::make_unique<char>(current_capacity_ + 1);
}

if (n < sz_) {
if (resized) {
std::strncpy(temp.get(), ptr_.get(), n);
temp.get()[n] = '';
} else {
ptr_.get()[n] = '';
}
} else if (n > sz_) {
if (resized) {
std::strncpy(temp.get(), ptr_.get(), sz_);
std::fill(temp.get() + sz_, temp.get() + n, ch);
temp.get()[n] = '';
} else {
std::fill(ptr_.get() + sz_, ptr_.get() + n, ch);
ptr_.get()[n] = '';
}
}

sz_ = n;
if (resized) {
ptr_ = std::move(temp);
}
}

void string::clear() noexcept {
current_capacity_ = default_capacity_;
ptr_ = std::make_unique<char>(current_capacity_ + 1);
ptr_.get()[0] = '';
sz_ = 0;
}

bool string::empty() const noexcept {
return sz_ == 0;
}

char& string::at(size_t idx) {
if (idx < 0 || idx >= sz_) {
throw std::out_of_range{"out of range memory access"};
}
return (*this)[idx];
}

const char& string::at(size_t idx) const {
if (idx < 0 || idx >= sz_) {
throw std::out_of_range{"out of range memory access"};
}
return (*this)[idx];
}

char& string::back() {
return (*this)[sz_ - 1];
}

const char& string::back() const {
return (*this)[sz_ - 1];
}

char& string::front() {
return (*this)[0];
}

const char& string::front() const {
return (*this)[0];
}

string& string::append(const string& rhs) {
(*this) += rhs;
return *this;
}

string& string::append(const char* rhs) {
(*this) += rhs;
return *this;
}

string& string::append(string&& rhs) {
(*this) += rhs;
return *this;
}

string& string::append(char ch) {
(*this) += ch;
return *this;
}

void string::push_back(char ch) {
(*this) += ch;
return;
}

string& string::assign(const string& rhs) {
(*this) = rhs;
return *this;
}

string& string::assign(const char* rhs) {
(*this) = rhs;
return *this;
}

string& string::assign(string&& rhs) {
(*this) = rhs;
return *this;
}

void string::swap(string &str) {
string temp{str};
str = *this;
*this = temp;
}

const char* string::c_str() const noexcept {
return ptr_.get();
}

const char* string::data() const noexcept {
return c_str();
}



/**************************************** member operator overloads*********************/

string& string::operator = (const string& rhs) {
if (this != &rhs) {
if (current_capacity_ != rhs.current_capacity_) {
current_capacity_ = rhs.current_capacity_;
ptr_ = std::make_unique<char>(current_capacity_ + 1);
}
sz_ = rhs.sz_;
std::strcpy(ptr_.get(), rhs.c_str());
}
return *this;
}

string& string::operator = (string&& rval) noexcept {
current_capacity_ = rval.current_capacity_;
sz_ = rval.sz_;
ptr_ = std::move(rval.ptr_);
return *this;
}

string& string::operator = (const char* c_string) {
sz_ = std::strlen(c_string);
auto appropriate_capacity = get_appropriate_capacity(sz_);
if (current_capacity_ != appropriate_capacity) {
current_capacity_ = appropriate_capacity;
ptr_ = std::make_unique<char>(current_capacity_ + 1);
}
std::strcpy(ptr_.get(), c_string);
return *this;
}

string& string::operator = (char ch) {
current_capacity_ = default_capacity_;
sz_ = 1;
ptr_ = std::make_unique<char>(current_capacity_ + 1);
ptr_.get()[0] = ch;
ptr_.get()[1] = '';
return *this;
}

string& string::operator += (const string& rhs) {
std::unique_ptr<char> temp;
auto appropriate_capacity = get_appropriate_capacity(sz_ + rhs.sz_);

if (current_capacity_ != appropriate_capacity) {
current_capacity_ = appropriate_capacity;
temp = std::make_unique<char>(current_capacity_ + 1);
std::strcpy(temp.get(), ptr_.get());
ptr_ = std::move(temp);
}

std::strcpy(ptr_.get() + sz_, rhs.c_str());
sz_ += rhs.sz_;

return *this;
}

string& string::operator += (const char* rhs) {
std::unique_ptr<char> temp;
auto rhs_sz = std::strlen(rhs);
auto appropriate_capacity = get_appropriate_capacity(sz_ + rhs_sz);

if (current_capacity_ != appropriate_capacity) {
current_capacity_ = appropriate_capacity;
temp = std::make_unique<char>(current_capacity_ + 1);
std::strcpy(temp.get(), ptr_.get());
ptr_ = std::move(temp);
}

std::strcpy(ptr_.get() + sz_, rhs);
sz_ += rhs_sz;

return *this;
}

string& string::operator += (char ch) {
auto appropriate_capacity = get_appropriate_capacity(sz_ + 1);
std::unique_ptr<char> temp;

if (current_capacity_ != appropriate_capacity) {
current_capacity_ = appropriate_capacity;
temp = std::make_unique<char>(current_capacity_ + 1);
strcpy(temp.get(), ptr_.get());
ptr_ = std::move(temp);
}
ptr_.get()[sz_] = ch;
ptr_.get()[sz_ + 1] = '';
sz_ += 1;

return *this;
}


string& string::operator += (string&& rval) {
std::unique_ptr<char> temp;
auto appropriate_capacity = get_appropriate_capacity(sz_ + rval.sz_);

if (current_capacity_ != appropriate_capacity) {
current_capacity_ = appropriate_capacity;
temp = std::make_unique<char>(current_capacity_ + 1);
std::strcpy(temp.get(), ptr_.get());
ptr_ = std::move(temp);
}

std::strcpy(ptr_.get() + sz_, rval.c_str());
sz_ += rval.sz_;

return *this;
}

char& string::operator (size_t idx) {
return ptr_.get()[idx];
}

const char& string::operator (size_t idx) const {
return ptr_.get()[idx];
}



/**************************************** friend operator overloads *********************/

std::ostream& operator << (std::ostream& out, const string& str) {
if (str.size() > 0) {
out.write(str.c_str(), str.size());
}
return out;
}

string operator + (const string& lhs, const string& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const string& lhs, const char* rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const char* lhs, const string& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (string&& lhs, string&& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (string&& lhs, const char* rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const char* lhs, string&& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const string& lhs, string&& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (string&& lhs, const string& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (const string& lhs, char rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (char lhs, const string& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (string&& lhs, char rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

string operator + (char lhs, string&& rhs) {
string temp{lhs};
temp += rhs;
return temp;
}

bool operator == (const string& lhs, const string& rhs) noexcept {
return (lhs.sz_ == rhs.sz_) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
}

bool operator == (const string& lhs, const char* rhs) noexcept {
return (lhs.sz_ == std::strlen(rhs)) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
}

bool operator == (const char* lhs, const string& rhs) noexcept {
return (strlen(lhs) == rhs.sz_) &&
((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
}

bool operator == (const string& lhs, char rhs) noexcept {
return (lhs.sz_ == 1) &&
(lhs.ptr_.get()[0] == rhs);
}

bool operator == (char lhs, const string& rhs) noexcept {
return (rhs.sz_ == 1) &&
(lhs == rhs.ptr_.get()[0]);
}

bool operator == (const string& lhs, string&& rhs) noexcept {
return (lhs.sz_ == rhs.sz_) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
}

bool operator == (string&& lhs, const string& rhs) noexcept {
return (lhs.sz_ == rhs.sz_) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
}

bool operator == (string&& lhs, string&& rhs) noexcept {
return (lhs.sz_ == rhs.sz_) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
}

bool operator == (string&& lhs, char rhs) noexcept {
return (lhs.sz_ == 1) &&
(lhs.ptr_.get()[0] == rhs);
}

bool operator == (char lhs, string&& rhs) noexcept {
return (rhs.sz_ == 1) &&
(rhs.ptr_.get()[0] == lhs);
}

bool operator == (string&& lhs, const char* rhs) noexcept {
return (lhs.sz_ == std::strlen(rhs)) &&
((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
}

bool operator == (const char* lhs, string && rhs) noexcept {
return (std::strlen(lhs) == rhs.sz_) &&
((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
}

bool operator != (const string& lhs, const string& rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (const string& lhs, const char* rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (const char* lhs, const string& rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (const string& lhs, char rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (char lhs, const string& rhs) noexcept {
return !(lhs == rhs);
}

bool operator != (const string& lhs, string&& rhs) noexcept {
return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
}

bool operator != (string&& lhs, const string& rhs) noexcept {
return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
}

bool operator != (string&& lhs, string&& rhs) noexcept {
return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
}

bool operator != (string&& lhs, char rhs) noexcept {
return (lhs.sz_ != 1) || (lhs.ptr_.get()[0] != rhs);
}

bool operator != (char lhs, string&& rhs) noexcept {
return (rhs.sz_ != 1) || (rhs.ptr_.get()[0] != lhs);
}

bool operator != (string&& lhs, const char* rhs) noexcept {
return (lhs.sz_ != std::strlen(rhs)) || (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) != 0);
}

bool operator != (const char* lhs, string && rhs) noexcept {
return (std::strlen(lhs) != rhs.sz_) || (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) != 0);
}



/**************************************** iterator related implementations *********************/

using iterator = string::iterator;

iterator::iterator(string *str, size_t index) noexcept
: str_{str}, index_{index} {
}

iterator::iterator(const iterator& itr) noexcept
: str_{itr.str_}, index_{itr.index_} {
}

iterator::iterator(iterator&& rval) noexcept
: str_{rval.str_}, index_{rval.index_} {
}

iterator::~iterator() noexcept {
str_ = nullptr;
index_ = 0;
}



iterator& iterator::operator = (const iterator& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

iterator& iterator::operator = (iterator&& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

bool iterator::operator != (const iterator& rhs) const noexcept {
return (str_ != rhs.str_) || (index_ != rhs.index_);
}

bool iterator::operator == (const iterator& rhs) const noexcept {
return (str_ == rhs.str_) && (index_ == rhs.index_);
}

iterator& iterator::operator ++ () noexcept {
++index_;
return *this;
}

iterator& iterator::operator ++ (int dummy) noexcept {
++(*this);
return *this;
}

iterator& iterator::operator -- () noexcept {
--index_;
return *this;
}

iterator& iterator::operator -- (int dummy) noexcept {
--(*this);
return *this;
}

char& iterator::operator * () const {
return (*str_)[index_];
}

iterator string::begin() {
return iterator(this);
}

iterator string::end() {
return iterator(this, sz_);
}



using const_iterator = string::const_iterator;

const_iterator::const_iterator(const string* str, size_t index) noexcept
: str_{str}, index_{index} {
}

const_iterator::const_iterator(const const_iterator& itr) noexcept
: str_{itr.str_}, index_{itr.index_} {
}

const_iterator::const_iterator(const_iterator&& rval) noexcept
: str_{rval.str_}, index_{rval.index_} {
}

const_iterator::~const_iterator() noexcept {
str_ = nullptr;
index_ = 0;
}



const_iterator& const_iterator::operator = (const const_iterator& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

const_iterator& const_iterator::operator = (const_iterator&& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

bool const_iterator::operator != (const const_iterator& rhs) const noexcept {
return (str_ != rhs.str_) || (index_ != rhs.index_);
}

bool const_iterator::operator == (const const_iterator& rhs) const noexcept {
return (str_ == rhs.str_) && (index_ == rhs.index_);
}

const_iterator& const_iterator::operator ++ () noexcept {
++index_;
return *this;
}

const_iterator& const_iterator::operator ++ (int dummy) noexcept {
++(*this);
return *this;
}

const_iterator& const_iterator::operator -- () noexcept {
--index_;
return *this;
}

const_iterator& const_iterator::operator -- (int dummy) noexcept {
--(*this);
return *this;
}

const char& const_iterator::operator * () const {
return (*str_)[index_];
}

const_iterator string::cbegin() {
return const_iterator(this, 0);
}

const_iterator string::cend() {
return const_iterator(this, sz_);
}



using reverse_iterator = string::reverse_iterator;

reverse_iterator::reverse_iterator(string *str, size_t index) noexcept
: str_{str}, index_{index} {
}

reverse_iterator::reverse_iterator(const reverse_iterator& itr) noexcept
: str_{itr.str_}, index_{itr.index_} {
}

reverse_iterator::reverse_iterator(reverse_iterator&& rval) noexcept
: str_{rval.str_}, index_{rval.index_} {
}

reverse_iterator::~reverse_iterator() noexcept {
str_ = nullptr;
index_ = 0;
}



reverse_iterator& reverse_iterator::operator = (const reverse_iterator& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

reverse_iterator& reverse_iterator::operator = (reverse_iterator&& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

bool reverse_iterator::operator != (const reverse_iterator& rhs) const noexcept {
return (str_ != rhs.str_) || (index_ != rhs.index_);
}

bool reverse_iterator::operator == (const reverse_iterator& rhs) const noexcept {
return (str_ == rhs.str_) && (index_ == rhs.index_);
}

reverse_iterator& reverse_iterator::operator ++ () noexcept {
--index_;
return *this;
}

reverse_iterator& reverse_iterator::operator ++ (int dummy) noexcept {
++(*this);
return *this;
}

reverse_iterator& reverse_iterator::operator -- () noexcept {
++index_;
return *this;
}

reverse_iterator& reverse_iterator::operator -- (int dummy) noexcept {
--(*this);
return *this;
}

char& reverse_iterator::operator * () const {
return (*str_)[index_];
}

reverse_iterator string::rbegin() {
return reverse_iterator(this, sz_ - 1);
}

reverse_iterator string::rend() {
return reverse_iterator(this, -1);
}



using reverse_const_iterator = string::reverse_const_iterator;

reverse_const_iterator::reverse_const_iterator(const string* str, size_t index) noexcept
: str_{str}, index_{index} {
}

reverse_const_iterator::reverse_const_iterator(const reverse_const_iterator& itr) noexcept
: str_{itr.str_}, index_{itr.index_} {
}

reverse_const_iterator::reverse_const_iterator(reverse_const_iterator&& rval) noexcept
: str_{rval.str_}, index_{rval.index_} {
}

reverse_const_iterator::~reverse_const_iterator() noexcept {
str_ = nullptr;
index_ = 0;
}



reverse_const_iterator& reverse_const_iterator::operator = (const reverse_const_iterator& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

reverse_const_iterator& reverse_const_iterator::operator = (reverse_const_iterator&& rhs) noexcept {
str_ = rhs.str_;
index_ = rhs.index_;
return *this;
}

bool reverse_const_iterator::operator != (const reverse_const_iterator& rhs) const noexcept {
return (str_ != rhs.str_) || (index_ != rhs.index_);
}

bool reverse_const_iterator::operator == (const reverse_const_iterator& rhs) const noexcept {
return (str_ == rhs.str_) && (index_ == rhs.index_);
}

reverse_const_iterator& reverse_const_iterator::operator ++ () noexcept {
--index_;
return *this;
}

reverse_const_iterator& reverse_const_iterator::operator ++ (int dummy) noexcept {
++(*this);
return *this;
}

reverse_const_iterator& reverse_const_iterator::operator -- () noexcept {
++index_;
return *this;
}

reverse_const_iterator& reverse_const_iterator::operator -- (int dummy) noexcept {
--(*this);
return *this;
}

const char& reverse_const_iterator::operator * () const {
return (*str_)[index_];
}

reverse_const_iterator string::crbegin() {
return reverse_const_iterator(this, sz_ - 1);
}

reverse_const_iterator string::crend() {
return reverse_const_iterator(this, -1);
}
} //kapil


Below is a test file which shows the usage



test_string.cpp



#include "my_string.h"

using namespace kapil;

int main() {
string x{"kapil"};
std::cout << " size : " << x.size() << " length : " << x.length() << " is empty : " << x.empty() << " at 2 : " << x.at(2) << " back : " <<
x.back() << " c_str : " << x.c_str() << " data : " << x.data() << std::endl;
x.clear();
x = "dev";
string y{" singh"};
x.append(y);
x.append(" is");
y.assign(" assigned");
x += " operator +";
x += y;

std::cout << " x : " << x << " x cap : " << x.capacity() << "n y : " << y << " y cap : " << y.capacity() << std::endl;
string added = "i am binary + " + y + string{" ravl add "} + 'x';
std::cout << " added : " << added << " added cap : " << added.capacity() << std::endl;
added = "kapil";
added.resize(10, 'k');
std::cout << " added resize 10 : " << added << " added cap : " << added.capacity() << std::endl;
added.resize(78, 'l');
std::cout << " added resize 78 : " << added << " added cap : " << added.capacity() << std::endl;
string s1 = "kapil";
s1.swap(added);
std::cout << " added : " << added << " s1 : " << s1 << std::endl;

for (auto it : s1) {
std::cout << it << " ";
}

std::cout << "n";
return 0;
}









share|improve this question









New contributor




kapil is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

























    1














    This is my implementation of string class similar to std::string and supports the following :
    a range-for loops,
    b iterators,
    c basic utility functions,
    d exponential capacity increase,
    e operator overloads



    I am looking for specific reviews on implementation of iterators, exponential capacity increase, usage of noexcept and implementations of some functions like : resize(), operator+=, operator=, operator +



    Thanks in advance for any inputs.



    mystring.h



    #ifndef MY_STRING_H_
    #define MY_STRING_H_

    #include <cstring>
    #include <iostream>
    #include <memory>
    #include <algorithm>
    #include <stdexcept>
    #include <limits>

    namespace kapil {
    class string final {
    private:
    // default capacity of empty string.
    static constexpr size_t default_capacity_ = 16;
    // current capacity of the string container.
    size_t current_capacity_;
    //size of string.
    size_t sz_;
    // pointer to character
    std::unique_ptr<char> ptr_;
    public:
    string();
    string(const string&);
    string(string&&) noexcept;
    string(const char*);
    explicit string(char);
    ~string() noexcept;

    size_t capacity() const noexcept;
    size_t size() const noexcept;
    size_t length() const noexcept;
    void resize(size_t, char ch = '');
    void clear() noexcept;
    bool empty() const noexcept;
    char& at(size_t);
    const char& at(size_t) const;
    char& back();
    const char& back() const;
    char& front();
    const char& front() const;
    string& append(const string&);
    string& append(const char*);
    string& append(string&&);
    string& append(char);
    void push_back(char);
    string& assign(const string&);
    string& assign(const char*);
    string& assign(string&&);
    void swap(string&);
    const char* c_str() const noexcept;
    const char* data() const noexcept;



    string& operator = (const string&);
    string& operator = (string&&) noexcept;
    string& operator = (const char*);
    string& operator = (char);
    string& operator += (const string&);
    string& operator += (const char*);
    string& operator += (char);
    string& operator += (string&&);
    char& operator (size_t);
    const char& operator (size_t) const;

    friend std::ostream& operator << (std::ostream&, const string&);
    friend string operator + (const string&, const string&);
    friend string operator + (const string&, const char*);
    friend string operator + (const char*, const string&);
    friend string operator + (string&&, string&&);
    friend string operator + (string&&, const char*);
    friend string operator + (const char*, string&&);
    friend string operator + (const string&, string&&);
    friend string operator + (string&&, const string&);
    friend string operator + (const string&, char);
    friend string operator + (char, const string&);
    friend string operator + (string&&, char);
    friend string operator + (char, string&&);
    friend bool operator == (const string&, const string&) noexcept;
    friend bool operator == (const string&, const char*) noexcept;
    friend bool operator == (const char*, const string&) noexcept;
    friend bool operator == (const string&, char) noexcept;
    friend bool operator == (char, const string&) noexcept;
    friend bool operator == (const string&, string&&) noexcept;
    friend bool operator == (string&&, const string&) noexcept;
    friend bool operator == (string&&, string&&) noexcept;
    friend bool operator == (string&&, char) noexcept;
    friend bool operator == (char, string&&) noexcept;
    friend bool operator == (const char*, string&&) noexcept;
    friend bool operator == (string&&, const char*) noexcept;
    friend bool operator != (const string&, const string&) noexcept;
    friend bool operator != (const string&, const char*) noexcept;
    friend bool operator != (const char*, const string&) noexcept;
    friend bool operator != (const string&, char) noexcept;
    friend bool operator != (char, const string&) noexcept;
    friend bool operator != (const string&, string&&) noexcept;
    friend bool operator != (string&&, const string&) noexcept;
    friend bool operator != (string&&, string&&) noexcept;
    friend bool operator != (string&&, char) noexcept;
    friend bool operator != (char, string&&) noexcept;
    friend bool operator != (const char*, string&&) noexcept;
    friend bool operator != (string&&, const char*) noexcept;

    class iterator
    {
    private:
    string* str_;
    size_t index_;
    public:
    iterator(string* = nullptr, size_t = 0) noexcept;
    iterator(const iterator&) noexcept;
    iterator(iterator&&) noexcept;
    ~iterator() noexcept;

    iterator& operator = (const iterator&) noexcept;
    iterator& operator = (iterator&&) noexcept;
    bool operator != (const iterator&) const noexcept;
    bool operator == (const iterator&) const noexcept;
    iterator& operator ++ () noexcept;
    iterator& operator ++ (int) noexcept;
    iterator& operator -- () noexcept;
    iterator& operator -- (int) noexcept;
    char& operator * () const;
    };

    iterator begin();
    iterator end();

    class const_iterator
    {
    private:
    const string* str_;
    size_t index_;
    public:
    const_iterator(const string*, size_t) noexcept;
    const_iterator(const const_iterator&) noexcept;
    const_iterator(const_iterator&&) noexcept;
    ~const_iterator() noexcept;

    const_iterator& operator = (const const_iterator&) noexcept;
    const_iterator& operator = (const_iterator&&) noexcept;
    bool operator != (const const_iterator&) const noexcept;
    bool operator == (const const_iterator&) const noexcept;
    const_iterator& operator ++ () noexcept;
    const_iterator& operator ++ (int) noexcept;
    const_iterator& operator -- () noexcept;
    const_iterator& operator -- (int) noexcept;
    const char& operator * () const;
    };

    const_iterator cbegin();
    const_iterator cend();

    class reverse_iterator
    {
    private:
    string* str_;
    size_t index_;
    public:
    reverse_iterator(string* = nullptr, size_t = 0) noexcept;
    reverse_iterator(const reverse_iterator&) noexcept;
    reverse_iterator(reverse_iterator&&) noexcept;
    ~reverse_iterator() noexcept;

    reverse_iterator& operator = (const reverse_iterator&) noexcept;
    reverse_iterator& operator = (reverse_iterator&&) noexcept;
    bool operator != (const reverse_iterator&) const noexcept;
    bool operator == (const reverse_iterator&) const noexcept;
    reverse_iterator& operator ++ () noexcept;
    reverse_iterator& operator ++ (int) noexcept;
    reverse_iterator& operator -- () noexcept;
    reverse_iterator& operator -- (int) noexcept;
    char& operator * () const;
    };

    reverse_iterator rbegin();
    reverse_iterator rend();

    class reverse_const_iterator
    {
    private:
    const string* str_;
    size_t index_;
    public:
    reverse_const_iterator(const string*, size_t) noexcept;
    reverse_const_iterator(const reverse_const_iterator&) noexcept;
    reverse_const_iterator(reverse_const_iterator&&) noexcept;
    ~reverse_const_iterator() noexcept;

    reverse_const_iterator& operator = (const reverse_const_iterator&) noexcept;
    reverse_const_iterator& operator = (reverse_const_iterator&&) noexcept;
    bool operator != (const reverse_const_iterator&) const noexcept;
    bool operator == (const reverse_const_iterator&) const noexcept;
    reverse_const_iterator& operator ++ () noexcept;
    reverse_const_iterator& operator ++ (int) noexcept;
    reverse_const_iterator& operator -- () noexcept;
    reverse_const_iterator& operator -- (int) noexcept;
    const char& operator * () const;
    };

    reverse_const_iterator crbegin();
    reverse_const_iterator crend();
    };
    } //kapil

    #endif


    my_string.cpp



    #include "my_string.h"

    namespace kapil {
    /*
    For the given new_string_length, the appropriate capacity is the
    next power of 2 that is greater than new_string_length.
    */
    size_t get_appropriate_capacity(size_t new_string_length) {
    size_t appropriate_capacity = 16;
    if ((static_cast<unsigned long>(new_string_length) << 1) > std::numeric_limits<size_t>::max()) {
    appropriate_capacity = new_string_length;
    } else {
    appropriate_capacity = 16;
    if (appropriate_capacity <= new_string_length) {
    if (!(new_string_length & (new_string_length - 1))) {
    appropriate_capacity = new_string_length << 1;
    } else {
    while (appropriate_capacity < new_string_length) {
    appropriate_capacity <<= 1;
    }
    }
    }
    }
    return appropriate_capacity;
    }

    /**************************************** member functions *********************/

    string::string()
    : current_capacity_{ default_capacity_ } {
    sz_ = 0;
    ptr_ = std::make_unique<char>(current_capacity_ + 1);
    ptr_.get()[0] = '';
    }

    string::string(const string& other) {
    current_capacity_ = other.current_capacity_;
    sz_ = other.sz_;
    ptr_ = std::make_unique<char>(current_capacity_ + 1);
    std::strcpy(ptr_.get(), other.ptr_.get());
    }

    string::string(string&& rval) noexcept
    : current_capacity_{ rval.current_capacity_ },
    sz_{ rval.sz_ },
    ptr_{ std::move(rval.ptr_) } {
    }

    string::string(const char* c_string) {
    sz_ = std::strlen(c_string);
    current_capacity_ = get_appropriate_capacity(sz_);
    ptr_ = std::make_unique<char>(current_capacity_ + 1);
    std::strcpy(ptr_.get(), c_string);
    }

    string::string(char ch) {
    sz_ = 1;
    current_capacity_ = default_capacity_;
    ptr_ = std::make_unique<char>(current_capacity_ + 1);
    ptr_.get()[0] = ch;
    ptr_.get()[1] = '';
    }

    string::~string() noexcept {
    current_capacity_ = 0;
    sz_ = 0;
    ptr_.reset(nullptr);
    };


    /**************************************** member functions *********************/

    size_t string::capacity() const noexcept {
    return current_capacity_;
    }

    size_t string::size() const noexcept {
    return sz_;
    }

    size_t string::length() const noexcept {
    return sz_;
    }

    void string::resize(size_t n, char ch) {
    if (n == sz_) {
    return;
    }

    size_t appropriate_capacity = get_appropriate_capacity(n);

    std::unique_ptr<char> temp;
    auto resized = bool{false};

    if (current_capacity_ != appropriate_capacity) {
    resized = true;
    current_capacity_ = appropriate_capacity;
    temp = std::make_unique<char>(current_capacity_ + 1);
    }

    if (n < sz_) {
    if (resized) {
    std::strncpy(temp.get(), ptr_.get(), n);
    temp.get()[n] = '';
    } else {
    ptr_.get()[n] = '';
    }
    } else if (n > sz_) {
    if (resized) {
    std::strncpy(temp.get(), ptr_.get(), sz_);
    std::fill(temp.get() + sz_, temp.get() + n, ch);
    temp.get()[n] = '';
    } else {
    std::fill(ptr_.get() + sz_, ptr_.get() + n, ch);
    ptr_.get()[n] = '';
    }
    }

    sz_ = n;
    if (resized) {
    ptr_ = std::move(temp);
    }
    }

    void string::clear() noexcept {
    current_capacity_ = default_capacity_;
    ptr_ = std::make_unique<char>(current_capacity_ + 1);
    ptr_.get()[0] = '';
    sz_ = 0;
    }

    bool string::empty() const noexcept {
    return sz_ == 0;
    }

    char& string::at(size_t idx) {
    if (idx < 0 || idx >= sz_) {
    throw std::out_of_range{"out of range memory access"};
    }
    return (*this)[idx];
    }

    const char& string::at(size_t idx) const {
    if (idx < 0 || idx >= sz_) {
    throw std::out_of_range{"out of range memory access"};
    }
    return (*this)[idx];
    }

    char& string::back() {
    return (*this)[sz_ - 1];
    }

    const char& string::back() const {
    return (*this)[sz_ - 1];
    }

    char& string::front() {
    return (*this)[0];
    }

    const char& string::front() const {
    return (*this)[0];
    }

    string& string::append(const string& rhs) {
    (*this) += rhs;
    return *this;
    }

    string& string::append(const char* rhs) {
    (*this) += rhs;
    return *this;
    }

    string& string::append(string&& rhs) {
    (*this) += rhs;
    return *this;
    }

    string& string::append(char ch) {
    (*this) += ch;
    return *this;
    }

    void string::push_back(char ch) {
    (*this) += ch;
    return;
    }

    string& string::assign(const string& rhs) {
    (*this) = rhs;
    return *this;
    }

    string& string::assign(const char* rhs) {
    (*this) = rhs;
    return *this;
    }

    string& string::assign(string&& rhs) {
    (*this) = rhs;
    return *this;
    }

    void string::swap(string &str) {
    string temp{str};
    str = *this;
    *this = temp;
    }

    const char* string::c_str() const noexcept {
    return ptr_.get();
    }

    const char* string::data() const noexcept {
    return c_str();
    }



    /**************************************** member operator overloads*********************/

    string& string::operator = (const string& rhs) {
    if (this != &rhs) {
    if (current_capacity_ != rhs.current_capacity_) {
    current_capacity_ = rhs.current_capacity_;
    ptr_ = std::make_unique<char>(current_capacity_ + 1);
    }
    sz_ = rhs.sz_;
    std::strcpy(ptr_.get(), rhs.c_str());
    }
    return *this;
    }

    string& string::operator = (string&& rval) noexcept {
    current_capacity_ = rval.current_capacity_;
    sz_ = rval.sz_;
    ptr_ = std::move(rval.ptr_);
    return *this;
    }

    string& string::operator = (const char* c_string) {
    sz_ = std::strlen(c_string);
    auto appropriate_capacity = get_appropriate_capacity(sz_);
    if (current_capacity_ != appropriate_capacity) {
    current_capacity_ = appropriate_capacity;
    ptr_ = std::make_unique<char>(current_capacity_ + 1);
    }
    std::strcpy(ptr_.get(), c_string);
    return *this;
    }

    string& string::operator = (char ch) {
    current_capacity_ = default_capacity_;
    sz_ = 1;
    ptr_ = std::make_unique<char>(current_capacity_ + 1);
    ptr_.get()[0] = ch;
    ptr_.get()[1] = '';
    return *this;
    }

    string& string::operator += (const string& rhs) {
    std::unique_ptr<char> temp;
    auto appropriate_capacity = get_appropriate_capacity(sz_ + rhs.sz_);

    if (current_capacity_ != appropriate_capacity) {
    current_capacity_ = appropriate_capacity;
    temp = std::make_unique<char>(current_capacity_ + 1);
    std::strcpy(temp.get(), ptr_.get());
    ptr_ = std::move(temp);
    }

    std::strcpy(ptr_.get() + sz_, rhs.c_str());
    sz_ += rhs.sz_;

    return *this;
    }

    string& string::operator += (const char* rhs) {
    std::unique_ptr<char> temp;
    auto rhs_sz = std::strlen(rhs);
    auto appropriate_capacity = get_appropriate_capacity(sz_ + rhs_sz);

    if (current_capacity_ != appropriate_capacity) {
    current_capacity_ = appropriate_capacity;
    temp = std::make_unique<char>(current_capacity_ + 1);
    std::strcpy(temp.get(), ptr_.get());
    ptr_ = std::move(temp);
    }

    std::strcpy(ptr_.get() + sz_, rhs);
    sz_ += rhs_sz;

    return *this;
    }

    string& string::operator += (char ch) {
    auto appropriate_capacity = get_appropriate_capacity(sz_ + 1);
    std::unique_ptr<char> temp;

    if (current_capacity_ != appropriate_capacity) {
    current_capacity_ = appropriate_capacity;
    temp = std::make_unique<char>(current_capacity_ + 1);
    strcpy(temp.get(), ptr_.get());
    ptr_ = std::move(temp);
    }
    ptr_.get()[sz_] = ch;
    ptr_.get()[sz_ + 1] = '';
    sz_ += 1;

    return *this;
    }


    string& string::operator += (string&& rval) {
    std::unique_ptr<char> temp;
    auto appropriate_capacity = get_appropriate_capacity(sz_ + rval.sz_);

    if (current_capacity_ != appropriate_capacity) {
    current_capacity_ = appropriate_capacity;
    temp = std::make_unique<char>(current_capacity_ + 1);
    std::strcpy(temp.get(), ptr_.get());
    ptr_ = std::move(temp);
    }

    std::strcpy(ptr_.get() + sz_, rval.c_str());
    sz_ += rval.sz_;

    return *this;
    }

    char& string::operator (size_t idx) {
    return ptr_.get()[idx];
    }

    const char& string::operator (size_t idx) const {
    return ptr_.get()[idx];
    }



    /**************************************** friend operator overloads *********************/

    std::ostream& operator << (std::ostream& out, const string& str) {
    if (str.size() > 0) {
    out.write(str.c_str(), str.size());
    }
    return out;
    }

    string operator + (const string& lhs, const string& rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (const string& lhs, const char* rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (const char* lhs, const string& rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (string&& lhs, string&& rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (string&& lhs, const char* rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (const char* lhs, string&& rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (const string& lhs, string&& rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (string&& lhs, const string& rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (const string& lhs, char rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (char lhs, const string& rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (string&& lhs, char rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    string operator + (char lhs, string&& rhs) {
    string temp{lhs};
    temp += rhs;
    return temp;
    }

    bool operator == (const string& lhs, const string& rhs) noexcept {
    return (lhs.sz_ == rhs.sz_) &&
    ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
    }

    bool operator == (const string& lhs, const char* rhs) noexcept {
    return (lhs.sz_ == std::strlen(rhs)) &&
    ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
    }

    bool operator == (const char* lhs, const string& rhs) noexcept {
    return (strlen(lhs) == rhs.sz_) &&
    ((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
    }

    bool operator == (const string& lhs, char rhs) noexcept {
    return (lhs.sz_ == 1) &&
    (lhs.ptr_.get()[0] == rhs);
    }

    bool operator == (char lhs, const string& rhs) noexcept {
    return (rhs.sz_ == 1) &&
    (lhs == rhs.ptr_.get()[0]);
    }

    bool operator == (const string& lhs, string&& rhs) noexcept {
    return (lhs.sz_ == rhs.sz_) &&
    ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
    }

    bool operator == (string&& lhs, const string& rhs) noexcept {
    return (lhs.sz_ == rhs.sz_) &&
    ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
    }

    bool operator == (string&& lhs, string&& rhs) noexcept {
    return (lhs.sz_ == rhs.sz_) &&
    ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
    }

    bool operator == (string&& lhs, char rhs) noexcept {
    return (lhs.sz_ == 1) &&
    (lhs.ptr_.get()[0] == rhs);
    }

    bool operator == (char lhs, string&& rhs) noexcept {
    return (rhs.sz_ == 1) &&
    (rhs.ptr_.get()[0] == lhs);
    }

    bool operator == (string&& lhs, const char* rhs) noexcept {
    return (lhs.sz_ == std::strlen(rhs)) &&
    ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
    }

    bool operator == (const char* lhs, string && rhs) noexcept {
    return (std::strlen(lhs) == rhs.sz_) &&
    ((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
    }

    bool operator != (const string& lhs, const string& rhs) noexcept {
    return !(lhs == rhs);
    }

    bool operator != (const string& lhs, const char* rhs) noexcept {
    return !(lhs == rhs);
    }

    bool operator != (const char* lhs, const string& rhs) noexcept {
    return !(lhs == rhs);
    }

    bool operator != (const string& lhs, char rhs) noexcept {
    return !(lhs == rhs);
    }

    bool operator != (char lhs, const string& rhs) noexcept {
    return !(lhs == rhs);
    }

    bool operator != (const string& lhs, string&& rhs) noexcept {
    return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
    }

    bool operator != (string&& lhs, const string& rhs) noexcept {
    return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
    }

    bool operator != (string&& lhs, string&& rhs) noexcept {
    return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
    }

    bool operator != (string&& lhs, char rhs) noexcept {
    return (lhs.sz_ != 1) || (lhs.ptr_.get()[0] != rhs);
    }

    bool operator != (char lhs, string&& rhs) noexcept {
    return (rhs.sz_ != 1) || (rhs.ptr_.get()[0] != lhs);
    }

    bool operator != (string&& lhs, const char* rhs) noexcept {
    return (lhs.sz_ != std::strlen(rhs)) || (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) != 0);
    }

    bool operator != (const char* lhs, string && rhs) noexcept {
    return (std::strlen(lhs) != rhs.sz_) || (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) != 0);
    }



    /**************************************** iterator related implementations *********************/

    using iterator = string::iterator;

    iterator::iterator(string *str, size_t index) noexcept
    : str_{str}, index_{index} {
    }

    iterator::iterator(const iterator& itr) noexcept
    : str_{itr.str_}, index_{itr.index_} {
    }

    iterator::iterator(iterator&& rval) noexcept
    : str_{rval.str_}, index_{rval.index_} {
    }

    iterator::~iterator() noexcept {
    str_ = nullptr;
    index_ = 0;
    }



    iterator& iterator::operator = (const iterator& rhs) noexcept {
    str_ = rhs.str_;
    index_ = rhs.index_;
    return *this;
    }

    iterator& iterator::operator = (iterator&& rhs) noexcept {
    str_ = rhs.str_;
    index_ = rhs.index_;
    return *this;
    }

    bool iterator::operator != (const iterator& rhs) const noexcept {
    return (str_ != rhs.str_) || (index_ != rhs.index_);
    }

    bool iterator::operator == (const iterator& rhs) const noexcept {
    return (str_ == rhs.str_) && (index_ == rhs.index_);
    }

    iterator& iterator::operator ++ () noexcept {
    ++index_;
    return *this;
    }

    iterator& iterator::operator ++ (int dummy) noexcept {
    ++(*this);
    return *this;
    }

    iterator& iterator::operator -- () noexcept {
    --index_;
    return *this;
    }

    iterator& iterator::operator -- (int dummy) noexcept {
    --(*this);
    return *this;
    }

    char& iterator::operator * () const {
    return (*str_)[index_];
    }

    iterator string::begin() {
    return iterator(this);
    }

    iterator string::end() {
    return iterator(this, sz_);
    }



    using const_iterator = string::const_iterator;

    const_iterator::const_iterator(const string* str, size_t index) noexcept
    : str_{str}, index_{index} {
    }

    const_iterator::const_iterator(const const_iterator& itr) noexcept
    : str_{itr.str_}, index_{itr.index_} {
    }

    const_iterator::const_iterator(const_iterator&& rval) noexcept
    : str_{rval.str_}, index_{rval.index_} {
    }

    const_iterator::~const_iterator() noexcept {
    str_ = nullptr;
    index_ = 0;
    }



    const_iterator& const_iterator::operator = (const const_iterator& rhs) noexcept {
    str_ = rhs.str_;
    index_ = rhs.index_;
    return *this;
    }

    const_iterator& const_iterator::operator = (const_iterator&& rhs) noexcept {
    str_ = rhs.str_;
    index_ = rhs.index_;
    return *this;
    }

    bool const_iterator::operator != (const const_iterator& rhs) const noexcept {
    return (str_ != rhs.str_) || (index_ != rhs.index_);
    }

    bool const_iterator::operator == (const const_iterator& rhs) const noexcept {
    return (str_ == rhs.str_) && (index_ == rhs.index_);
    }

    const_iterator& const_iterator::operator ++ () noexcept {
    ++index_;
    return *this;
    }

    const_iterator& const_iterator::operator ++ (int dummy) noexcept {
    ++(*this);
    return *this;
    }

    const_iterator& const_iterator::operator -- () noexcept {
    --index_;
    return *this;
    }

    const_iterator& const_iterator::operator -- (int dummy) noexcept {
    --(*this);
    return *this;
    }

    const char& const_iterator::operator * () const {
    return (*str_)[index_];
    }

    const_iterator string::cbegin() {
    return const_iterator(this, 0);
    }

    const_iterator string::cend() {
    return const_iterator(this, sz_);
    }



    using reverse_iterator = string::reverse_iterator;

    reverse_iterator::reverse_iterator(string *str, size_t index) noexcept
    : str_{str}, index_{index} {
    }

    reverse_iterator::reverse_iterator(const reverse_iterator& itr) noexcept
    : str_{itr.str_}, index_{itr.index_} {
    }

    reverse_iterator::reverse_iterator(reverse_iterator&& rval) noexcept
    : str_{rval.str_}, index_{rval.index_} {
    }

    reverse_iterator::~reverse_iterator() noexcept {
    str_ = nullptr;
    index_ = 0;
    }



    reverse_iterator& reverse_iterator::operator = (const reverse_iterator& rhs) noexcept {
    str_ = rhs.str_;
    index_ = rhs.index_;
    return *this;
    }

    reverse_iterator& reverse_iterator::operator = (reverse_iterator&& rhs) noexcept {
    str_ = rhs.str_;
    index_ = rhs.index_;
    return *this;
    }

    bool reverse_iterator::operator != (const reverse_iterator& rhs) const noexcept {
    return (str_ != rhs.str_) || (index_ != rhs.index_);
    }

    bool reverse_iterator::operator == (const reverse_iterator& rhs) const noexcept {
    return (str_ == rhs.str_) && (index_ == rhs.index_);
    }

    reverse_iterator& reverse_iterator::operator ++ () noexcept {
    --index_;
    return *this;
    }

    reverse_iterator& reverse_iterator::operator ++ (int dummy) noexcept {
    ++(*this);
    return *this;
    }

    reverse_iterator& reverse_iterator::operator -- () noexcept {
    ++index_;
    return *this;
    }

    reverse_iterator& reverse_iterator::operator -- (int dummy) noexcept {
    --(*this);
    return *this;
    }

    char& reverse_iterator::operator * () const {
    return (*str_)[index_];
    }

    reverse_iterator string::rbegin() {
    return reverse_iterator(this, sz_ - 1);
    }

    reverse_iterator string::rend() {
    return reverse_iterator(this, -1);
    }



    using reverse_const_iterator = string::reverse_const_iterator;

    reverse_const_iterator::reverse_const_iterator(const string* str, size_t index) noexcept
    : str_{str}, index_{index} {
    }

    reverse_const_iterator::reverse_const_iterator(const reverse_const_iterator& itr) noexcept
    : str_{itr.str_}, index_{itr.index_} {
    }

    reverse_const_iterator::reverse_const_iterator(reverse_const_iterator&& rval) noexcept
    : str_{rval.str_}, index_{rval.index_} {
    }

    reverse_const_iterator::~reverse_const_iterator() noexcept {
    str_ = nullptr;
    index_ = 0;
    }



    reverse_const_iterator& reverse_const_iterator::operator = (const reverse_const_iterator& rhs) noexcept {
    str_ = rhs.str_;
    index_ = rhs.index_;
    return *this;
    }

    reverse_const_iterator& reverse_const_iterator::operator = (reverse_const_iterator&& rhs) noexcept {
    str_ = rhs.str_;
    index_ = rhs.index_;
    return *this;
    }

    bool reverse_const_iterator::operator != (const reverse_const_iterator& rhs) const noexcept {
    return (str_ != rhs.str_) || (index_ != rhs.index_);
    }

    bool reverse_const_iterator::operator == (const reverse_const_iterator& rhs) const noexcept {
    return (str_ == rhs.str_) && (index_ == rhs.index_);
    }

    reverse_const_iterator& reverse_const_iterator::operator ++ () noexcept {
    --index_;
    return *this;
    }

    reverse_const_iterator& reverse_const_iterator::operator ++ (int dummy) noexcept {
    ++(*this);
    return *this;
    }

    reverse_const_iterator& reverse_const_iterator::operator -- () noexcept {
    ++index_;
    return *this;
    }

    reverse_const_iterator& reverse_const_iterator::operator -- (int dummy) noexcept {
    --(*this);
    return *this;
    }

    const char& reverse_const_iterator::operator * () const {
    return (*str_)[index_];
    }

    reverse_const_iterator string::crbegin() {
    return reverse_const_iterator(this, sz_ - 1);
    }

    reverse_const_iterator string::crend() {
    return reverse_const_iterator(this, -1);
    }
    } //kapil


    Below is a test file which shows the usage



    test_string.cpp



    #include "my_string.h"

    using namespace kapil;

    int main() {
    string x{"kapil"};
    std::cout << " size : " << x.size() << " length : " << x.length() << " is empty : " << x.empty() << " at 2 : " << x.at(2) << " back : " <<
    x.back() << " c_str : " << x.c_str() << " data : " << x.data() << std::endl;
    x.clear();
    x = "dev";
    string y{" singh"};
    x.append(y);
    x.append(" is");
    y.assign(" assigned");
    x += " operator +";
    x += y;

    std::cout << " x : " << x << " x cap : " << x.capacity() << "n y : " << y << " y cap : " << y.capacity() << std::endl;
    string added = "i am binary + " + y + string{" ravl add "} + 'x';
    std::cout << " added : " << added << " added cap : " << added.capacity() << std::endl;
    added = "kapil";
    added.resize(10, 'k');
    std::cout << " added resize 10 : " << added << " added cap : " << added.capacity() << std::endl;
    added.resize(78, 'l');
    std::cout << " added resize 78 : " << added << " added cap : " << added.capacity() << std::endl;
    string s1 = "kapil";
    s1.swap(added);
    std::cout << " added : " << added << " s1 : " << s1 << std::endl;

    for (auto it : s1) {
    std::cout << it << " ";
    }

    std::cout << "n";
    return 0;
    }









    share|improve this question









    New contributor




    kapil is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.























      1












      1








      1


      1





      This is my implementation of string class similar to std::string and supports the following :
      a range-for loops,
      b iterators,
      c basic utility functions,
      d exponential capacity increase,
      e operator overloads



      I am looking for specific reviews on implementation of iterators, exponential capacity increase, usage of noexcept and implementations of some functions like : resize(), operator+=, operator=, operator +



      Thanks in advance for any inputs.



      mystring.h



      #ifndef MY_STRING_H_
      #define MY_STRING_H_

      #include <cstring>
      #include <iostream>
      #include <memory>
      #include <algorithm>
      #include <stdexcept>
      #include <limits>

      namespace kapil {
      class string final {
      private:
      // default capacity of empty string.
      static constexpr size_t default_capacity_ = 16;
      // current capacity of the string container.
      size_t current_capacity_;
      //size of string.
      size_t sz_;
      // pointer to character
      std::unique_ptr<char> ptr_;
      public:
      string();
      string(const string&);
      string(string&&) noexcept;
      string(const char*);
      explicit string(char);
      ~string() noexcept;

      size_t capacity() const noexcept;
      size_t size() const noexcept;
      size_t length() const noexcept;
      void resize(size_t, char ch = '');
      void clear() noexcept;
      bool empty() const noexcept;
      char& at(size_t);
      const char& at(size_t) const;
      char& back();
      const char& back() const;
      char& front();
      const char& front() const;
      string& append(const string&);
      string& append(const char*);
      string& append(string&&);
      string& append(char);
      void push_back(char);
      string& assign(const string&);
      string& assign(const char*);
      string& assign(string&&);
      void swap(string&);
      const char* c_str() const noexcept;
      const char* data() const noexcept;



      string& operator = (const string&);
      string& operator = (string&&) noexcept;
      string& operator = (const char*);
      string& operator = (char);
      string& operator += (const string&);
      string& operator += (const char*);
      string& operator += (char);
      string& operator += (string&&);
      char& operator (size_t);
      const char& operator (size_t) const;

      friend std::ostream& operator << (std::ostream&, const string&);
      friend string operator + (const string&, const string&);
      friend string operator + (const string&, const char*);
      friend string operator + (const char*, const string&);
      friend string operator + (string&&, string&&);
      friend string operator + (string&&, const char*);
      friend string operator + (const char*, string&&);
      friend string operator + (const string&, string&&);
      friend string operator + (string&&, const string&);
      friend string operator + (const string&, char);
      friend string operator + (char, const string&);
      friend string operator + (string&&, char);
      friend string operator + (char, string&&);
      friend bool operator == (const string&, const string&) noexcept;
      friend bool operator == (const string&, const char*) noexcept;
      friend bool operator == (const char*, const string&) noexcept;
      friend bool operator == (const string&, char) noexcept;
      friend bool operator == (char, const string&) noexcept;
      friend bool operator == (const string&, string&&) noexcept;
      friend bool operator == (string&&, const string&) noexcept;
      friend bool operator == (string&&, string&&) noexcept;
      friend bool operator == (string&&, char) noexcept;
      friend bool operator == (char, string&&) noexcept;
      friend bool operator == (const char*, string&&) noexcept;
      friend bool operator == (string&&, const char*) noexcept;
      friend bool operator != (const string&, const string&) noexcept;
      friend bool operator != (const string&, const char*) noexcept;
      friend bool operator != (const char*, const string&) noexcept;
      friend bool operator != (const string&, char) noexcept;
      friend bool operator != (char, const string&) noexcept;
      friend bool operator != (const string&, string&&) noexcept;
      friend bool operator != (string&&, const string&) noexcept;
      friend bool operator != (string&&, string&&) noexcept;
      friend bool operator != (string&&, char) noexcept;
      friend bool operator != (char, string&&) noexcept;
      friend bool operator != (const char*, string&&) noexcept;
      friend bool operator != (string&&, const char*) noexcept;

      class iterator
      {
      private:
      string* str_;
      size_t index_;
      public:
      iterator(string* = nullptr, size_t = 0) noexcept;
      iterator(const iterator&) noexcept;
      iterator(iterator&&) noexcept;
      ~iterator() noexcept;

      iterator& operator = (const iterator&) noexcept;
      iterator& operator = (iterator&&) noexcept;
      bool operator != (const iterator&) const noexcept;
      bool operator == (const iterator&) const noexcept;
      iterator& operator ++ () noexcept;
      iterator& operator ++ (int) noexcept;
      iterator& operator -- () noexcept;
      iterator& operator -- (int) noexcept;
      char& operator * () const;
      };

      iterator begin();
      iterator end();

      class const_iterator
      {
      private:
      const string* str_;
      size_t index_;
      public:
      const_iterator(const string*, size_t) noexcept;
      const_iterator(const const_iterator&) noexcept;
      const_iterator(const_iterator&&) noexcept;
      ~const_iterator() noexcept;

      const_iterator& operator = (const const_iterator&) noexcept;
      const_iterator& operator = (const_iterator&&) noexcept;
      bool operator != (const const_iterator&) const noexcept;
      bool operator == (const const_iterator&) const noexcept;
      const_iterator& operator ++ () noexcept;
      const_iterator& operator ++ (int) noexcept;
      const_iterator& operator -- () noexcept;
      const_iterator& operator -- (int) noexcept;
      const char& operator * () const;
      };

      const_iterator cbegin();
      const_iterator cend();

      class reverse_iterator
      {
      private:
      string* str_;
      size_t index_;
      public:
      reverse_iterator(string* = nullptr, size_t = 0) noexcept;
      reverse_iterator(const reverse_iterator&) noexcept;
      reverse_iterator(reverse_iterator&&) noexcept;
      ~reverse_iterator() noexcept;

      reverse_iterator& operator = (const reverse_iterator&) noexcept;
      reverse_iterator& operator = (reverse_iterator&&) noexcept;
      bool operator != (const reverse_iterator&) const noexcept;
      bool operator == (const reverse_iterator&) const noexcept;
      reverse_iterator& operator ++ () noexcept;
      reverse_iterator& operator ++ (int) noexcept;
      reverse_iterator& operator -- () noexcept;
      reverse_iterator& operator -- (int) noexcept;
      char& operator * () const;
      };

      reverse_iterator rbegin();
      reverse_iterator rend();

      class reverse_const_iterator
      {
      private:
      const string* str_;
      size_t index_;
      public:
      reverse_const_iterator(const string*, size_t) noexcept;
      reverse_const_iterator(const reverse_const_iterator&) noexcept;
      reverse_const_iterator(reverse_const_iterator&&) noexcept;
      ~reverse_const_iterator() noexcept;

      reverse_const_iterator& operator = (const reverse_const_iterator&) noexcept;
      reverse_const_iterator& operator = (reverse_const_iterator&&) noexcept;
      bool operator != (const reverse_const_iterator&) const noexcept;
      bool operator == (const reverse_const_iterator&) const noexcept;
      reverse_const_iterator& operator ++ () noexcept;
      reverse_const_iterator& operator ++ (int) noexcept;
      reverse_const_iterator& operator -- () noexcept;
      reverse_const_iterator& operator -- (int) noexcept;
      const char& operator * () const;
      };

      reverse_const_iterator crbegin();
      reverse_const_iterator crend();
      };
      } //kapil

      #endif


      my_string.cpp



      #include "my_string.h"

      namespace kapil {
      /*
      For the given new_string_length, the appropriate capacity is the
      next power of 2 that is greater than new_string_length.
      */
      size_t get_appropriate_capacity(size_t new_string_length) {
      size_t appropriate_capacity = 16;
      if ((static_cast<unsigned long>(new_string_length) << 1) > std::numeric_limits<size_t>::max()) {
      appropriate_capacity = new_string_length;
      } else {
      appropriate_capacity = 16;
      if (appropriate_capacity <= new_string_length) {
      if (!(new_string_length & (new_string_length - 1))) {
      appropriate_capacity = new_string_length << 1;
      } else {
      while (appropriate_capacity < new_string_length) {
      appropriate_capacity <<= 1;
      }
      }
      }
      }
      return appropriate_capacity;
      }

      /**************************************** member functions *********************/

      string::string()
      : current_capacity_{ default_capacity_ } {
      sz_ = 0;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      ptr_.get()[0] = '';
      }

      string::string(const string& other) {
      current_capacity_ = other.current_capacity_;
      sz_ = other.sz_;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(ptr_.get(), other.ptr_.get());
      }

      string::string(string&& rval) noexcept
      : current_capacity_{ rval.current_capacity_ },
      sz_{ rval.sz_ },
      ptr_{ std::move(rval.ptr_) } {
      }

      string::string(const char* c_string) {
      sz_ = std::strlen(c_string);
      current_capacity_ = get_appropriate_capacity(sz_);
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(ptr_.get(), c_string);
      }

      string::string(char ch) {
      sz_ = 1;
      current_capacity_ = default_capacity_;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      ptr_.get()[0] = ch;
      ptr_.get()[1] = '';
      }

      string::~string() noexcept {
      current_capacity_ = 0;
      sz_ = 0;
      ptr_.reset(nullptr);
      };


      /**************************************** member functions *********************/

      size_t string::capacity() const noexcept {
      return current_capacity_;
      }

      size_t string::size() const noexcept {
      return sz_;
      }

      size_t string::length() const noexcept {
      return sz_;
      }

      void string::resize(size_t n, char ch) {
      if (n == sz_) {
      return;
      }

      size_t appropriate_capacity = get_appropriate_capacity(n);

      std::unique_ptr<char> temp;
      auto resized = bool{false};

      if (current_capacity_ != appropriate_capacity) {
      resized = true;
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      }

      if (n < sz_) {
      if (resized) {
      std::strncpy(temp.get(), ptr_.get(), n);
      temp.get()[n] = '';
      } else {
      ptr_.get()[n] = '';
      }
      } else if (n > sz_) {
      if (resized) {
      std::strncpy(temp.get(), ptr_.get(), sz_);
      std::fill(temp.get() + sz_, temp.get() + n, ch);
      temp.get()[n] = '';
      } else {
      std::fill(ptr_.get() + sz_, ptr_.get() + n, ch);
      ptr_.get()[n] = '';
      }
      }

      sz_ = n;
      if (resized) {
      ptr_ = std::move(temp);
      }
      }

      void string::clear() noexcept {
      current_capacity_ = default_capacity_;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      ptr_.get()[0] = '';
      sz_ = 0;
      }

      bool string::empty() const noexcept {
      return sz_ == 0;
      }

      char& string::at(size_t idx) {
      if (idx < 0 || idx >= sz_) {
      throw std::out_of_range{"out of range memory access"};
      }
      return (*this)[idx];
      }

      const char& string::at(size_t idx) const {
      if (idx < 0 || idx >= sz_) {
      throw std::out_of_range{"out of range memory access"};
      }
      return (*this)[idx];
      }

      char& string::back() {
      return (*this)[sz_ - 1];
      }

      const char& string::back() const {
      return (*this)[sz_ - 1];
      }

      char& string::front() {
      return (*this)[0];
      }

      const char& string::front() const {
      return (*this)[0];
      }

      string& string::append(const string& rhs) {
      (*this) += rhs;
      return *this;
      }

      string& string::append(const char* rhs) {
      (*this) += rhs;
      return *this;
      }

      string& string::append(string&& rhs) {
      (*this) += rhs;
      return *this;
      }

      string& string::append(char ch) {
      (*this) += ch;
      return *this;
      }

      void string::push_back(char ch) {
      (*this) += ch;
      return;
      }

      string& string::assign(const string& rhs) {
      (*this) = rhs;
      return *this;
      }

      string& string::assign(const char* rhs) {
      (*this) = rhs;
      return *this;
      }

      string& string::assign(string&& rhs) {
      (*this) = rhs;
      return *this;
      }

      void string::swap(string &str) {
      string temp{str};
      str = *this;
      *this = temp;
      }

      const char* string::c_str() const noexcept {
      return ptr_.get();
      }

      const char* string::data() const noexcept {
      return c_str();
      }



      /**************************************** member operator overloads*********************/

      string& string::operator = (const string& rhs) {
      if (this != &rhs) {
      if (current_capacity_ != rhs.current_capacity_) {
      current_capacity_ = rhs.current_capacity_;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      }
      sz_ = rhs.sz_;
      std::strcpy(ptr_.get(), rhs.c_str());
      }
      return *this;
      }

      string& string::operator = (string&& rval) noexcept {
      current_capacity_ = rval.current_capacity_;
      sz_ = rval.sz_;
      ptr_ = std::move(rval.ptr_);
      return *this;
      }

      string& string::operator = (const char* c_string) {
      sz_ = std::strlen(c_string);
      auto appropriate_capacity = get_appropriate_capacity(sz_);
      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      }
      std::strcpy(ptr_.get(), c_string);
      return *this;
      }

      string& string::operator = (char ch) {
      current_capacity_ = default_capacity_;
      sz_ = 1;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      ptr_.get()[0] = ch;
      ptr_.get()[1] = '';
      return *this;
      }

      string& string::operator += (const string& rhs) {
      std::unique_ptr<char> temp;
      auto appropriate_capacity = get_appropriate_capacity(sz_ + rhs.sz_);

      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(temp.get(), ptr_.get());
      ptr_ = std::move(temp);
      }

      std::strcpy(ptr_.get() + sz_, rhs.c_str());
      sz_ += rhs.sz_;

      return *this;
      }

      string& string::operator += (const char* rhs) {
      std::unique_ptr<char> temp;
      auto rhs_sz = std::strlen(rhs);
      auto appropriate_capacity = get_appropriate_capacity(sz_ + rhs_sz);

      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(temp.get(), ptr_.get());
      ptr_ = std::move(temp);
      }

      std::strcpy(ptr_.get() + sz_, rhs);
      sz_ += rhs_sz;

      return *this;
      }

      string& string::operator += (char ch) {
      auto appropriate_capacity = get_appropriate_capacity(sz_ + 1);
      std::unique_ptr<char> temp;

      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      strcpy(temp.get(), ptr_.get());
      ptr_ = std::move(temp);
      }
      ptr_.get()[sz_] = ch;
      ptr_.get()[sz_ + 1] = '';
      sz_ += 1;

      return *this;
      }


      string& string::operator += (string&& rval) {
      std::unique_ptr<char> temp;
      auto appropriate_capacity = get_appropriate_capacity(sz_ + rval.sz_);

      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(temp.get(), ptr_.get());
      ptr_ = std::move(temp);
      }

      std::strcpy(ptr_.get() + sz_, rval.c_str());
      sz_ += rval.sz_;

      return *this;
      }

      char& string::operator (size_t idx) {
      return ptr_.get()[idx];
      }

      const char& string::operator (size_t idx) const {
      return ptr_.get()[idx];
      }



      /**************************************** friend operator overloads *********************/

      std::ostream& operator << (std::ostream& out, const string& str) {
      if (str.size() > 0) {
      out.write(str.c_str(), str.size());
      }
      return out;
      }

      string operator + (const string& lhs, const string& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const string& lhs, const char* rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const char* lhs, const string& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (string&& lhs, string&& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (string&& lhs, const char* rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const char* lhs, string&& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const string& lhs, string&& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (string&& lhs, const string& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const string& lhs, char rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (char lhs, const string& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (string&& lhs, char rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (char lhs, string&& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      bool operator == (const string& lhs, const string& rhs) noexcept {
      return (lhs.sz_ == rhs.sz_) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
      }

      bool operator == (const string& lhs, const char* rhs) noexcept {
      return (lhs.sz_ == std::strlen(rhs)) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
      }

      bool operator == (const char* lhs, const string& rhs) noexcept {
      return (strlen(lhs) == rhs.sz_) &&
      ((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
      }

      bool operator == (const string& lhs, char rhs) noexcept {
      return (lhs.sz_ == 1) &&
      (lhs.ptr_.get()[0] == rhs);
      }

      bool operator == (char lhs, const string& rhs) noexcept {
      return (rhs.sz_ == 1) &&
      (lhs == rhs.ptr_.get()[0]);
      }

      bool operator == (const string& lhs, string&& rhs) noexcept {
      return (lhs.sz_ == rhs.sz_) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
      }

      bool operator == (string&& lhs, const string& rhs) noexcept {
      return (lhs.sz_ == rhs.sz_) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
      }

      bool operator == (string&& lhs, string&& rhs) noexcept {
      return (lhs.sz_ == rhs.sz_) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
      }

      bool operator == (string&& lhs, char rhs) noexcept {
      return (lhs.sz_ == 1) &&
      (lhs.ptr_.get()[0] == rhs);
      }

      bool operator == (char lhs, string&& rhs) noexcept {
      return (rhs.sz_ == 1) &&
      (rhs.ptr_.get()[0] == lhs);
      }

      bool operator == (string&& lhs, const char* rhs) noexcept {
      return (lhs.sz_ == std::strlen(rhs)) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
      }

      bool operator == (const char* lhs, string && rhs) noexcept {
      return (std::strlen(lhs) == rhs.sz_) &&
      ((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
      }

      bool operator != (const string& lhs, const string& rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (const string& lhs, const char* rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (const char* lhs, const string& rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (const string& lhs, char rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (char lhs, const string& rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (const string& lhs, string&& rhs) noexcept {
      return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
      }

      bool operator != (string&& lhs, const string& rhs) noexcept {
      return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
      }

      bool operator != (string&& lhs, string&& rhs) noexcept {
      return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
      }

      bool operator != (string&& lhs, char rhs) noexcept {
      return (lhs.sz_ != 1) || (lhs.ptr_.get()[0] != rhs);
      }

      bool operator != (char lhs, string&& rhs) noexcept {
      return (rhs.sz_ != 1) || (rhs.ptr_.get()[0] != lhs);
      }

      bool operator != (string&& lhs, const char* rhs) noexcept {
      return (lhs.sz_ != std::strlen(rhs)) || (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) != 0);
      }

      bool operator != (const char* lhs, string && rhs) noexcept {
      return (std::strlen(lhs) != rhs.sz_) || (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) != 0);
      }



      /**************************************** iterator related implementations *********************/

      using iterator = string::iterator;

      iterator::iterator(string *str, size_t index) noexcept
      : str_{str}, index_{index} {
      }

      iterator::iterator(const iterator& itr) noexcept
      : str_{itr.str_}, index_{itr.index_} {
      }

      iterator::iterator(iterator&& rval) noexcept
      : str_{rval.str_}, index_{rval.index_} {
      }

      iterator::~iterator() noexcept {
      str_ = nullptr;
      index_ = 0;
      }



      iterator& iterator::operator = (const iterator& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      iterator& iterator::operator = (iterator&& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      bool iterator::operator != (const iterator& rhs) const noexcept {
      return (str_ != rhs.str_) || (index_ != rhs.index_);
      }

      bool iterator::operator == (const iterator& rhs) const noexcept {
      return (str_ == rhs.str_) && (index_ == rhs.index_);
      }

      iterator& iterator::operator ++ () noexcept {
      ++index_;
      return *this;
      }

      iterator& iterator::operator ++ (int dummy) noexcept {
      ++(*this);
      return *this;
      }

      iterator& iterator::operator -- () noexcept {
      --index_;
      return *this;
      }

      iterator& iterator::operator -- (int dummy) noexcept {
      --(*this);
      return *this;
      }

      char& iterator::operator * () const {
      return (*str_)[index_];
      }

      iterator string::begin() {
      return iterator(this);
      }

      iterator string::end() {
      return iterator(this, sz_);
      }



      using const_iterator = string::const_iterator;

      const_iterator::const_iterator(const string* str, size_t index) noexcept
      : str_{str}, index_{index} {
      }

      const_iterator::const_iterator(const const_iterator& itr) noexcept
      : str_{itr.str_}, index_{itr.index_} {
      }

      const_iterator::const_iterator(const_iterator&& rval) noexcept
      : str_{rval.str_}, index_{rval.index_} {
      }

      const_iterator::~const_iterator() noexcept {
      str_ = nullptr;
      index_ = 0;
      }



      const_iterator& const_iterator::operator = (const const_iterator& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      const_iterator& const_iterator::operator = (const_iterator&& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      bool const_iterator::operator != (const const_iterator& rhs) const noexcept {
      return (str_ != rhs.str_) || (index_ != rhs.index_);
      }

      bool const_iterator::operator == (const const_iterator& rhs) const noexcept {
      return (str_ == rhs.str_) && (index_ == rhs.index_);
      }

      const_iterator& const_iterator::operator ++ () noexcept {
      ++index_;
      return *this;
      }

      const_iterator& const_iterator::operator ++ (int dummy) noexcept {
      ++(*this);
      return *this;
      }

      const_iterator& const_iterator::operator -- () noexcept {
      --index_;
      return *this;
      }

      const_iterator& const_iterator::operator -- (int dummy) noexcept {
      --(*this);
      return *this;
      }

      const char& const_iterator::operator * () const {
      return (*str_)[index_];
      }

      const_iterator string::cbegin() {
      return const_iterator(this, 0);
      }

      const_iterator string::cend() {
      return const_iterator(this, sz_);
      }



      using reverse_iterator = string::reverse_iterator;

      reverse_iterator::reverse_iterator(string *str, size_t index) noexcept
      : str_{str}, index_{index} {
      }

      reverse_iterator::reverse_iterator(const reverse_iterator& itr) noexcept
      : str_{itr.str_}, index_{itr.index_} {
      }

      reverse_iterator::reverse_iterator(reverse_iterator&& rval) noexcept
      : str_{rval.str_}, index_{rval.index_} {
      }

      reverse_iterator::~reverse_iterator() noexcept {
      str_ = nullptr;
      index_ = 0;
      }



      reverse_iterator& reverse_iterator::operator = (const reverse_iterator& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      reverse_iterator& reverse_iterator::operator = (reverse_iterator&& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      bool reverse_iterator::operator != (const reverse_iterator& rhs) const noexcept {
      return (str_ != rhs.str_) || (index_ != rhs.index_);
      }

      bool reverse_iterator::operator == (const reverse_iterator& rhs) const noexcept {
      return (str_ == rhs.str_) && (index_ == rhs.index_);
      }

      reverse_iterator& reverse_iterator::operator ++ () noexcept {
      --index_;
      return *this;
      }

      reverse_iterator& reverse_iterator::operator ++ (int dummy) noexcept {
      ++(*this);
      return *this;
      }

      reverse_iterator& reverse_iterator::operator -- () noexcept {
      ++index_;
      return *this;
      }

      reverse_iterator& reverse_iterator::operator -- (int dummy) noexcept {
      --(*this);
      return *this;
      }

      char& reverse_iterator::operator * () const {
      return (*str_)[index_];
      }

      reverse_iterator string::rbegin() {
      return reverse_iterator(this, sz_ - 1);
      }

      reverse_iterator string::rend() {
      return reverse_iterator(this, -1);
      }



      using reverse_const_iterator = string::reverse_const_iterator;

      reverse_const_iterator::reverse_const_iterator(const string* str, size_t index) noexcept
      : str_{str}, index_{index} {
      }

      reverse_const_iterator::reverse_const_iterator(const reverse_const_iterator& itr) noexcept
      : str_{itr.str_}, index_{itr.index_} {
      }

      reverse_const_iterator::reverse_const_iterator(reverse_const_iterator&& rval) noexcept
      : str_{rval.str_}, index_{rval.index_} {
      }

      reverse_const_iterator::~reverse_const_iterator() noexcept {
      str_ = nullptr;
      index_ = 0;
      }



      reverse_const_iterator& reverse_const_iterator::operator = (const reverse_const_iterator& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      reverse_const_iterator& reverse_const_iterator::operator = (reverse_const_iterator&& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      bool reverse_const_iterator::operator != (const reverse_const_iterator& rhs) const noexcept {
      return (str_ != rhs.str_) || (index_ != rhs.index_);
      }

      bool reverse_const_iterator::operator == (const reverse_const_iterator& rhs) const noexcept {
      return (str_ == rhs.str_) && (index_ == rhs.index_);
      }

      reverse_const_iterator& reverse_const_iterator::operator ++ () noexcept {
      --index_;
      return *this;
      }

      reverse_const_iterator& reverse_const_iterator::operator ++ (int dummy) noexcept {
      ++(*this);
      return *this;
      }

      reverse_const_iterator& reverse_const_iterator::operator -- () noexcept {
      ++index_;
      return *this;
      }

      reverse_const_iterator& reverse_const_iterator::operator -- (int dummy) noexcept {
      --(*this);
      return *this;
      }

      const char& reverse_const_iterator::operator * () const {
      return (*str_)[index_];
      }

      reverse_const_iterator string::crbegin() {
      return reverse_const_iterator(this, sz_ - 1);
      }

      reverse_const_iterator string::crend() {
      return reverse_const_iterator(this, -1);
      }
      } //kapil


      Below is a test file which shows the usage



      test_string.cpp



      #include "my_string.h"

      using namespace kapil;

      int main() {
      string x{"kapil"};
      std::cout << " size : " << x.size() << " length : " << x.length() << " is empty : " << x.empty() << " at 2 : " << x.at(2) << " back : " <<
      x.back() << " c_str : " << x.c_str() << " data : " << x.data() << std::endl;
      x.clear();
      x = "dev";
      string y{" singh"};
      x.append(y);
      x.append(" is");
      y.assign(" assigned");
      x += " operator +";
      x += y;

      std::cout << " x : " << x << " x cap : " << x.capacity() << "n y : " << y << " y cap : " << y.capacity() << std::endl;
      string added = "i am binary + " + y + string{" ravl add "} + 'x';
      std::cout << " added : " << added << " added cap : " << added.capacity() << std::endl;
      added = "kapil";
      added.resize(10, 'k');
      std::cout << " added resize 10 : " << added << " added cap : " << added.capacity() << std::endl;
      added.resize(78, 'l');
      std::cout << " added resize 78 : " << added << " added cap : " << added.capacity() << std::endl;
      string s1 = "kapil";
      s1.swap(added);
      std::cout << " added : " << added << " s1 : " << s1 << std::endl;

      for (auto it : s1) {
      std::cout << it << " ";
      }

      std::cout << "n";
      return 0;
      }









      share|improve this question









      New contributor




      kapil is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      This is my implementation of string class similar to std::string and supports the following :
      a range-for loops,
      b iterators,
      c basic utility functions,
      d exponential capacity increase,
      e operator overloads



      I am looking for specific reviews on implementation of iterators, exponential capacity increase, usage of noexcept and implementations of some functions like : resize(), operator+=, operator=, operator +



      Thanks in advance for any inputs.



      mystring.h



      #ifndef MY_STRING_H_
      #define MY_STRING_H_

      #include <cstring>
      #include <iostream>
      #include <memory>
      #include <algorithm>
      #include <stdexcept>
      #include <limits>

      namespace kapil {
      class string final {
      private:
      // default capacity of empty string.
      static constexpr size_t default_capacity_ = 16;
      // current capacity of the string container.
      size_t current_capacity_;
      //size of string.
      size_t sz_;
      // pointer to character
      std::unique_ptr<char> ptr_;
      public:
      string();
      string(const string&);
      string(string&&) noexcept;
      string(const char*);
      explicit string(char);
      ~string() noexcept;

      size_t capacity() const noexcept;
      size_t size() const noexcept;
      size_t length() const noexcept;
      void resize(size_t, char ch = '');
      void clear() noexcept;
      bool empty() const noexcept;
      char& at(size_t);
      const char& at(size_t) const;
      char& back();
      const char& back() const;
      char& front();
      const char& front() const;
      string& append(const string&);
      string& append(const char*);
      string& append(string&&);
      string& append(char);
      void push_back(char);
      string& assign(const string&);
      string& assign(const char*);
      string& assign(string&&);
      void swap(string&);
      const char* c_str() const noexcept;
      const char* data() const noexcept;



      string& operator = (const string&);
      string& operator = (string&&) noexcept;
      string& operator = (const char*);
      string& operator = (char);
      string& operator += (const string&);
      string& operator += (const char*);
      string& operator += (char);
      string& operator += (string&&);
      char& operator (size_t);
      const char& operator (size_t) const;

      friend std::ostream& operator << (std::ostream&, const string&);
      friend string operator + (const string&, const string&);
      friend string operator + (const string&, const char*);
      friend string operator + (const char*, const string&);
      friend string operator + (string&&, string&&);
      friend string operator + (string&&, const char*);
      friend string operator + (const char*, string&&);
      friend string operator + (const string&, string&&);
      friend string operator + (string&&, const string&);
      friend string operator + (const string&, char);
      friend string operator + (char, const string&);
      friend string operator + (string&&, char);
      friend string operator + (char, string&&);
      friend bool operator == (const string&, const string&) noexcept;
      friend bool operator == (const string&, const char*) noexcept;
      friend bool operator == (const char*, const string&) noexcept;
      friend bool operator == (const string&, char) noexcept;
      friend bool operator == (char, const string&) noexcept;
      friend bool operator == (const string&, string&&) noexcept;
      friend bool operator == (string&&, const string&) noexcept;
      friend bool operator == (string&&, string&&) noexcept;
      friend bool operator == (string&&, char) noexcept;
      friend bool operator == (char, string&&) noexcept;
      friend bool operator == (const char*, string&&) noexcept;
      friend bool operator == (string&&, const char*) noexcept;
      friend bool operator != (const string&, const string&) noexcept;
      friend bool operator != (const string&, const char*) noexcept;
      friend bool operator != (const char*, const string&) noexcept;
      friend bool operator != (const string&, char) noexcept;
      friend bool operator != (char, const string&) noexcept;
      friend bool operator != (const string&, string&&) noexcept;
      friend bool operator != (string&&, const string&) noexcept;
      friend bool operator != (string&&, string&&) noexcept;
      friend bool operator != (string&&, char) noexcept;
      friend bool operator != (char, string&&) noexcept;
      friend bool operator != (const char*, string&&) noexcept;
      friend bool operator != (string&&, const char*) noexcept;

      class iterator
      {
      private:
      string* str_;
      size_t index_;
      public:
      iterator(string* = nullptr, size_t = 0) noexcept;
      iterator(const iterator&) noexcept;
      iterator(iterator&&) noexcept;
      ~iterator() noexcept;

      iterator& operator = (const iterator&) noexcept;
      iterator& operator = (iterator&&) noexcept;
      bool operator != (const iterator&) const noexcept;
      bool operator == (const iterator&) const noexcept;
      iterator& operator ++ () noexcept;
      iterator& operator ++ (int) noexcept;
      iterator& operator -- () noexcept;
      iterator& operator -- (int) noexcept;
      char& operator * () const;
      };

      iterator begin();
      iterator end();

      class const_iterator
      {
      private:
      const string* str_;
      size_t index_;
      public:
      const_iterator(const string*, size_t) noexcept;
      const_iterator(const const_iterator&) noexcept;
      const_iterator(const_iterator&&) noexcept;
      ~const_iterator() noexcept;

      const_iterator& operator = (const const_iterator&) noexcept;
      const_iterator& operator = (const_iterator&&) noexcept;
      bool operator != (const const_iterator&) const noexcept;
      bool operator == (const const_iterator&) const noexcept;
      const_iterator& operator ++ () noexcept;
      const_iterator& operator ++ (int) noexcept;
      const_iterator& operator -- () noexcept;
      const_iterator& operator -- (int) noexcept;
      const char& operator * () const;
      };

      const_iterator cbegin();
      const_iterator cend();

      class reverse_iterator
      {
      private:
      string* str_;
      size_t index_;
      public:
      reverse_iterator(string* = nullptr, size_t = 0) noexcept;
      reverse_iterator(const reverse_iterator&) noexcept;
      reverse_iterator(reverse_iterator&&) noexcept;
      ~reverse_iterator() noexcept;

      reverse_iterator& operator = (const reverse_iterator&) noexcept;
      reverse_iterator& operator = (reverse_iterator&&) noexcept;
      bool operator != (const reverse_iterator&) const noexcept;
      bool operator == (const reverse_iterator&) const noexcept;
      reverse_iterator& operator ++ () noexcept;
      reverse_iterator& operator ++ (int) noexcept;
      reverse_iterator& operator -- () noexcept;
      reverse_iterator& operator -- (int) noexcept;
      char& operator * () const;
      };

      reverse_iterator rbegin();
      reverse_iterator rend();

      class reverse_const_iterator
      {
      private:
      const string* str_;
      size_t index_;
      public:
      reverse_const_iterator(const string*, size_t) noexcept;
      reverse_const_iterator(const reverse_const_iterator&) noexcept;
      reverse_const_iterator(reverse_const_iterator&&) noexcept;
      ~reverse_const_iterator() noexcept;

      reverse_const_iterator& operator = (const reverse_const_iterator&) noexcept;
      reverse_const_iterator& operator = (reverse_const_iterator&&) noexcept;
      bool operator != (const reverse_const_iterator&) const noexcept;
      bool operator == (const reverse_const_iterator&) const noexcept;
      reverse_const_iterator& operator ++ () noexcept;
      reverse_const_iterator& operator ++ (int) noexcept;
      reverse_const_iterator& operator -- () noexcept;
      reverse_const_iterator& operator -- (int) noexcept;
      const char& operator * () const;
      };

      reverse_const_iterator crbegin();
      reverse_const_iterator crend();
      };
      } //kapil

      #endif


      my_string.cpp



      #include "my_string.h"

      namespace kapil {
      /*
      For the given new_string_length, the appropriate capacity is the
      next power of 2 that is greater than new_string_length.
      */
      size_t get_appropriate_capacity(size_t new_string_length) {
      size_t appropriate_capacity = 16;
      if ((static_cast<unsigned long>(new_string_length) << 1) > std::numeric_limits<size_t>::max()) {
      appropriate_capacity = new_string_length;
      } else {
      appropriate_capacity = 16;
      if (appropriate_capacity <= new_string_length) {
      if (!(new_string_length & (new_string_length - 1))) {
      appropriate_capacity = new_string_length << 1;
      } else {
      while (appropriate_capacity < new_string_length) {
      appropriate_capacity <<= 1;
      }
      }
      }
      }
      return appropriate_capacity;
      }

      /**************************************** member functions *********************/

      string::string()
      : current_capacity_{ default_capacity_ } {
      sz_ = 0;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      ptr_.get()[0] = '';
      }

      string::string(const string& other) {
      current_capacity_ = other.current_capacity_;
      sz_ = other.sz_;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(ptr_.get(), other.ptr_.get());
      }

      string::string(string&& rval) noexcept
      : current_capacity_{ rval.current_capacity_ },
      sz_{ rval.sz_ },
      ptr_{ std::move(rval.ptr_) } {
      }

      string::string(const char* c_string) {
      sz_ = std::strlen(c_string);
      current_capacity_ = get_appropriate_capacity(sz_);
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(ptr_.get(), c_string);
      }

      string::string(char ch) {
      sz_ = 1;
      current_capacity_ = default_capacity_;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      ptr_.get()[0] = ch;
      ptr_.get()[1] = '';
      }

      string::~string() noexcept {
      current_capacity_ = 0;
      sz_ = 0;
      ptr_.reset(nullptr);
      };


      /**************************************** member functions *********************/

      size_t string::capacity() const noexcept {
      return current_capacity_;
      }

      size_t string::size() const noexcept {
      return sz_;
      }

      size_t string::length() const noexcept {
      return sz_;
      }

      void string::resize(size_t n, char ch) {
      if (n == sz_) {
      return;
      }

      size_t appropriate_capacity = get_appropriate_capacity(n);

      std::unique_ptr<char> temp;
      auto resized = bool{false};

      if (current_capacity_ != appropriate_capacity) {
      resized = true;
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      }

      if (n < sz_) {
      if (resized) {
      std::strncpy(temp.get(), ptr_.get(), n);
      temp.get()[n] = '';
      } else {
      ptr_.get()[n] = '';
      }
      } else if (n > sz_) {
      if (resized) {
      std::strncpy(temp.get(), ptr_.get(), sz_);
      std::fill(temp.get() + sz_, temp.get() + n, ch);
      temp.get()[n] = '';
      } else {
      std::fill(ptr_.get() + sz_, ptr_.get() + n, ch);
      ptr_.get()[n] = '';
      }
      }

      sz_ = n;
      if (resized) {
      ptr_ = std::move(temp);
      }
      }

      void string::clear() noexcept {
      current_capacity_ = default_capacity_;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      ptr_.get()[0] = '';
      sz_ = 0;
      }

      bool string::empty() const noexcept {
      return sz_ == 0;
      }

      char& string::at(size_t idx) {
      if (idx < 0 || idx >= sz_) {
      throw std::out_of_range{"out of range memory access"};
      }
      return (*this)[idx];
      }

      const char& string::at(size_t idx) const {
      if (idx < 0 || idx >= sz_) {
      throw std::out_of_range{"out of range memory access"};
      }
      return (*this)[idx];
      }

      char& string::back() {
      return (*this)[sz_ - 1];
      }

      const char& string::back() const {
      return (*this)[sz_ - 1];
      }

      char& string::front() {
      return (*this)[0];
      }

      const char& string::front() const {
      return (*this)[0];
      }

      string& string::append(const string& rhs) {
      (*this) += rhs;
      return *this;
      }

      string& string::append(const char* rhs) {
      (*this) += rhs;
      return *this;
      }

      string& string::append(string&& rhs) {
      (*this) += rhs;
      return *this;
      }

      string& string::append(char ch) {
      (*this) += ch;
      return *this;
      }

      void string::push_back(char ch) {
      (*this) += ch;
      return;
      }

      string& string::assign(const string& rhs) {
      (*this) = rhs;
      return *this;
      }

      string& string::assign(const char* rhs) {
      (*this) = rhs;
      return *this;
      }

      string& string::assign(string&& rhs) {
      (*this) = rhs;
      return *this;
      }

      void string::swap(string &str) {
      string temp{str};
      str = *this;
      *this = temp;
      }

      const char* string::c_str() const noexcept {
      return ptr_.get();
      }

      const char* string::data() const noexcept {
      return c_str();
      }



      /**************************************** member operator overloads*********************/

      string& string::operator = (const string& rhs) {
      if (this != &rhs) {
      if (current_capacity_ != rhs.current_capacity_) {
      current_capacity_ = rhs.current_capacity_;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      }
      sz_ = rhs.sz_;
      std::strcpy(ptr_.get(), rhs.c_str());
      }
      return *this;
      }

      string& string::operator = (string&& rval) noexcept {
      current_capacity_ = rval.current_capacity_;
      sz_ = rval.sz_;
      ptr_ = std::move(rval.ptr_);
      return *this;
      }

      string& string::operator = (const char* c_string) {
      sz_ = std::strlen(c_string);
      auto appropriate_capacity = get_appropriate_capacity(sz_);
      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      }
      std::strcpy(ptr_.get(), c_string);
      return *this;
      }

      string& string::operator = (char ch) {
      current_capacity_ = default_capacity_;
      sz_ = 1;
      ptr_ = std::make_unique<char>(current_capacity_ + 1);
      ptr_.get()[0] = ch;
      ptr_.get()[1] = '';
      return *this;
      }

      string& string::operator += (const string& rhs) {
      std::unique_ptr<char> temp;
      auto appropriate_capacity = get_appropriate_capacity(sz_ + rhs.sz_);

      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(temp.get(), ptr_.get());
      ptr_ = std::move(temp);
      }

      std::strcpy(ptr_.get() + sz_, rhs.c_str());
      sz_ += rhs.sz_;

      return *this;
      }

      string& string::operator += (const char* rhs) {
      std::unique_ptr<char> temp;
      auto rhs_sz = std::strlen(rhs);
      auto appropriate_capacity = get_appropriate_capacity(sz_ + rhs_sz);

      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(temp.get(), ptr_.get());
      ptr_ = std::move(temp);
      }

      std::strcpy(ptr_.get() + sz_, rhs);
      sz_ += rhs_sz;

      return *this;
      }

      string& string::operator += (char ch) {
      auto appropriate_capacity = get_appropriate_capacity(sz_ + 1);
      std::unique_ptr<char> temp;

      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      strcpy(temp.get(), ptr_.get());
      ptr_ = std::move(temp);
      }
      ptr_.get()[sz_] = ch;
      ptr_.get()[sz_ + 1] = '';
      sz_ += 1;

      return *this;
      }


      string& string::operator += (string&& rval) {
      std::unique_ptr<char> temp;
      auto appropriate_capacity = get_appropriate_capacity(sz_ + rval.sz_);

      if (current_capacity_ != appropriate_capacity) {
      current_capacity_ = appropriate_capacity;
      temp = std::make_unique<char>(current_capacity_ + 1);
      std::strcpy(temp.get(), ptr_.get());
      ptr_ = std::move(temp);
      }

      std::strcpy(ptr_.get() + sz_, rval.c_str());
      sz_ += rval.sz_;

      return *this;
      }

      char& string::operator (size_t idx) {
      return ptr_.get()[idx];
      }

      const char& string::operator (size_t idx) const {
      return ptr_.get()[idx];
      }



      /**************************************** friend operator overloads *********************/

      std::ostream& operator << (std::ostream& out, const string& str) {
      if (str.size() > 0) {
      out.write(str.c_str(), str.size());
      }
      return out;
      }

      string operator + (const string& lhs, const string& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const string& lhs, const char* rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const char* lhs, const string& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (string&& lhs, string&& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (string&& lhs, const char* rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const char* lhs, string&& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const string& lhs, string&& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (string&& lhs, const string& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (const string& lhs, char rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (char lhs, const string& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (string&& lhs, char rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      string operator + (char lhs, string&& rhs) {
      string temp{lhs};
      temp += rhs;
      return temp;
      }

      bool operator == (const string& lhs, const string& rhs) noexcept {
      return (lhs.sz_ == rhs.sz_) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
      }

      bool operator == (const string& lhs, const char* rhs) noexcept {
      return (lhs.sz_ == std::strlen(rhs)) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
      }

      bool operator == (const char* lhs, const string& rhs) noexcept {
      return (strlen(lhs) == rhs.sz_) &&
      ((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
      }

      bool operator == (const string& lhs, char rhs) noexcept {
      return (lhs.sz_ == 1) &&
      (lhs.ptr_.get()[0] == rhs);
      }

      bool operator == (char lhs, const string& rhs) noexcept {
      return (rhs.sz_ == 1) &&
      (lhs == rhs.ptr_.get()[0]);
      }

      bool operator == (const string& lhs, string&& rhs) noexcept {
      return (lhs.sz_ == rhs.sz_) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
      }

      bool operator == (string&& lhs, const string& rhs) noexcept {
      return (lhs.sz_ == rhs.sz_) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
      }

      bool operator == (string&& lhs, string&& rhs) noexcept {
      return (lhs.sz_ == rhs.sz_) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) == 0));
      }

      bool operator == (string&& lhs, char rhs) noexcept {
      return (lhs.sz_ == 1) &&
      (lhs.ptr_.get()[0] == rhs);
      }

      bool operator == (char lhs, string&& rhs) noexcept {
      return (rhs.sz_ == 1) &&
      (rhs.ptr_.get()[0] == lhs);
      }

      bool operator == (string&& lhs, const char* rhs) noexcept {
      return (lhs.sz_ == std::strlen(rhs)) &&
      ((lhs.sz_ == 0) ? true : (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) == 0));
      }

      bool operator == (const char* lhs, string && rhs) noexcept {
      return (std::strlen(lhs) == rhs.sz_) &&
      ((rhs.sz_ == 0) ? true : (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) == 0));
      }

      bool operator != (const string& lhs, const string& rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (const string& lhs, const char* rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (const char* lhs, const string& rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (const string& lhs, char rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (char lhs, const string& rhs) noexcept {
      return !(lhs == rhs);
      }

      bool operator != (const string& lhs, string&& rhs) noexcept {
      return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
      }

      bool operator != (string&& lhs, const string& rhs) noexcept {
      return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
      }

      bool operator != (string&& lhs, string&& rhs) noexcept {
      return (lhs.sz_ != rhs.sz_) || (std::strncmp(lhs.ptr_.get(), rhs.ptr_.get(), lhs.sz_) != 0);
      }

      bool operator != (string&& lhs, char rhs) noexcept {
      return (lhs.sz_ != 1) || (lhs.ptr_.get()[0] != rhs);
      }

      bool operator != (char lhs, string&& rhs) noexcept {
      return (rhs.sz_ != 1) || (rhs.ptr_.get()[0] != lhs);
      }

      bool operator != (string&& lhs, const char* rhs) noexcept {
      return (lhs.sz_ != std::strlen(rhs)) || (std::strncmp(lhs.ptr_.get(), rhs, lhs.sz_) != 0);
      }

      bool operator != (const char* lhs, string && rhs) noexcept {
      return (std::strlen(lhs) != rhs.sz_) || (std::strncmp(lhs, rhs.ptr_.get(), rhs.sz_) != 0);
      }



      /**************************************** iterator related implementations *********************/

      using iterator = string::iterator;

      iterator::iterator(string *str, size_t index) noexcept
      : str_{str}, index_{index} {
      }

      iterator::iterator(const iterator& itr) noexcept
      : str_{itr.str_}, index_{itr.index_} {
      }

      iterator::iterator(iterator&& rval) noexcept
      : str_{rval.str_}, index_{rval.index_} {
      }

      iterator::~iterator() noexcept {
      str_ = nullptr;
      index_ = 0;
      }



      iterator& iterator::operator = (const iterator& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      iterator& iterator::operator = (iterator&& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      bool iterator::operator != (const iterator& rhs) const noexcept {
      return (str_ != rhs.str_) || (index_ != rhs.index_);
      }

      bool iterator::operator == (const iterator& rhs) const noexcept {
      return (str_ == rhs.str_) && (index_ == rhs.index_);
      }

      iterator& iterator::operator ++ () noexcept {
      ++index_;
      return *this;
      }

      iterator& iterator::operator ++ (int dummy) noexcept {
      ++(*this);
      return *this;
      }

      iterator& iterator::operator -- () noexcept {
      --index_;
      return *this;
      }

      iterator& iterator::operator -- (int dummy) noexcept {
      --(*this);
      return *this;
      }

      char& iterator::operator * () const {
      return (*str_)[index_];
      }

      iterator string::begin() {
      return iterator(this);
      }

      iterator string::end() {
      return iterator(this, sz_);
      }



      using const_iterator = string::const_iterator;

      const_iterator::const_iterator(const string* str, size_t index) noexcept
      : str_{str}, index_{index} {
      }

      const_iterator::const_iterator(const const_iterator& itr) noexcept
      : str_{itr.str_}, index_{itr.index_} {
      }

      const_iterator::const_iterator(const_iterator&& rval) noexcept
      : str_{rval.str_}, index_{rval.index_} {
      }

      const_iterator::~const_iterator() noexcept {
      str_ = nullptr;
      index_ = 0;
      }



      const_iterator& const_iterator::operator = (const const_iterator& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      const_iterator& const_iterator::operator = (const_iterator&& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      bool const_iterator::operator != (const const_iterator& rhs) const noexcept {
      return (str_ != rhs.str_) || (index_ != rhs.index_);
      }

      bool const_iterator::operator == (const const_iterator& rhs) const noexcept {
      return (str_ == rhs.str_) && (index_ == rhs.index_);
      }

      const_iterator& const_iterator::operator ++ () noexcept {
      ++index_;
      return *this;
      }

      const_iterator& const_iterator::operator ++ (int dummy) noexcept {
      ++(*this);
      return *this;
      }

      const_iterator& const_iterator::operator -- () noexcept {
      --index_;
      return *this;
      }

      const_iterator& const_iterator::operator -- (int dummy) noexcept {
      --(*this);
      return *this;
      }

      const char& const_iterator::operator * () const {
      return (*str_)[index_];
      }

      const_iterator string::cbegin() {
      return const_iterator(this, 0);
      }

      const_iterator string::cend() {
      return const_iterator(this, sz_);
      }



      using reverse_iterator = string::reverse_iterator;

      reverse_iterator::reverse_iterator(string *str, size_t index) noexcept
      : str_{str}, index_{index} {
      }

      reverse_iterator::reverse_iterator(const reverse_iterator& itr) noexcept
      : str_{itr.str_}, index_{itr.index_} {
      }

      reverse_iterator::reverse_iterator(reverse_iterator&& rval) noexcept
      : str_{rval.str_}, index_{rval.index_} {
      }

      reverse_iterator::~reverse_iterator() noexcept {
      str_ = nullptr;
      index_ = 0;
      }



      reverse_iterator& reverse_iterator::operator = (const reverse_iterator& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      reverse_iterator& reverse_iterator::operator = (reverse_iterator&& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      bool reverse_iterator::operator != (const reverse_iterator& rhs) const noexcept {
      return (str_ != rhs.str_) || (index_ != rhs.index_);
      }

      bool reverse_iterator::operator == (const reverse_iterator& rhs) const noexcept {
      return (str_ == rhs.str_) && (index_ == rhs.index_);
      }

      reverse_iterator& reverse_iterator::operator ++ () noexcept {
      --index_;
      return *this;
      }

      reverse_iterator& reverse_iterator::operator ++ (int dummy) noexcept {
      ++(*this);
      return *this;
      }

      reverse_iterator& reverse_iterator::operator -- () noexcept {
      ++index_;
      return *this;
      }

      reverse_iterator& reverse_iterator::operator -- (int dummy) noexcept {
      --(*this);
      return *this;
      }

      char& reverse_iterator::operator * () const {
      return (*str_)[index_];
      }

      reverse_iterator string::rbegin() {
      return reverse_iterator(this, sz_ - 1);
      }

      reverse_iterator string::rend() {
      return reverse_iterator(this, -1);
      }



      using reverse_const_iterator = string::reverse_const_iterator;

      reverse_const_iterator::reverse_const_iterator(const string* str, size_t index) noexcept
      : str_{str}, index_{index} {
      }

      reverse_const_iterator::reverse_const_iterator(const reverse_const_iterator& itr) noexcept
      : str_{itr.str_}, index_{itr.index_} {
      }

      reverse_const_iterator::reverse_const_iterator(reverse_const_iterator&& rval) noexcept
      : str_{rval.str_}, index_{rval.index_} {
      }

      reverse_const_iterator::~reverse_const_iterator() noexcept {
      str_ = nullptr;
      index_ = 0;
      }



      reverse_const_iterator& reverse_const_iterator::operator = (const reverse_const_iterator& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      reverse_const_iterator& reverse_const_iterator::operator = (reverse_const_iterator&& rhs) noexcept {
      str_ = rhs.str_;
      index_ = rhs.index_;
      return *this;
      }

      bool reverse_const_iterator::operator != (const reverse_const_iterator& rhs) const noexcept {
      return (str_ != rhs.str_) || (index_ != rhs.index_);
      }

      bool reverse_const_iterator::operator == (const reverse_const_iterator& rhs) const noexcept {
      return (str_ == rhs.str_) && (index_ == rhs.index_);
      }

      reverse_const_iterator& reverse_const_iterator::operator ++ () noexcept {
      --index_;
      return *this;
      }

      reverse_const_iterator& reverse_const_iterator::operator ++ (int dummy) noexcept {
      ++(*this);
      return *this;
      }

      reverse_const_iterator& reverse_const_iterator::operator -- () noexcept {
      ++index_;
      return *this;
      }

      reverse_const_iterator& reverse_const_iterator::operator -- (int dummy) noexcept {
      --(*this);
      return *this;
      }

      const char& reverse_const_iterator::operator * () const {
      return (*str_)[index_];
      }

      reverse_const_iterator string::crbegin() {
      return reverse_const_iterator(this, sz_ - 1);
      }

      reverse_const_iterator string::crend() {
      return reverse_const_iterator(this, -1);
      }
      } //kapil


      Below is a test file which shows the usage



      test_string.cpp



      #include "my_string.h"

      using namespace kapil;

      int main() {
      string x{"kapil"};
      std::cout << " size : " << x.size() << " length : " << x.length() << " is empty : " << x.empty() << " at 2 : " << x.at(2) << " back : " <<
      x.back() << " c_str : " << x.c_str() << " data : " << x.data() << std::endl;
      x.clear();
      x = "dev";
      string y{" singh"};
      x.append(y);
      x.append(" is");
      y.assign(" assigned");
      x += " operator +";
      x += y;

      std::cout << " x : " << x << " x cap : " << x.capacity() << "n y : " << y << " y cap : " << y.capacity() << std::endl;
      string added = "i am binary + " + y + string{" ravl add "} + 'x';
      std::cout << " added : " << added << " added cap : " << added.capacity() << std::endl;
      added = "kapil";
      added.resize(10, 'k');
      std::cout << " added resize 10 : " << added << " added cap : " << added.capacity() << std::endl;
      added.resize(78, 'l');
      std::cout << " added resize 78 : " << added << " added cap : " << added.capacity() << std::endl;
      string s1 = "kapil";
      s1.swap(added);
      std::cout << " added : " << added << " s1 : " << s1 << std::endl;

      for (auto it : s1) {
      std::cout << it << " ";
      }

      std::cout << "n";
      return 0;
      }






      strings c++11






      share|improve this question









      New contributor




      kapil is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question









      New contributor




      kapil is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question








      edited 10 mins ago





















      New contributor




      kapil is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 50 mins ago









      kapil

      62




      62




      New contributor




      kapil is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      kapil is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      kapil is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });






          kapil is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210707%2fc-string-implementation-providing-support-for-range-for-loop-iterators-expo%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          kapil is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          kapil is a new contributor. Be nice, and check out our Code of Conduct.













          kapil is a new contributor. Be nice, and check out our Code of Conduct.












          kapil is a new contributor. Be nice, and check out our Code of Conduct.
















          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210707%2fc-string-implementation-providing-support-for-range-for-loop-iterators-expo%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Morgemoulin

          Scott Moir

          Souastre