I'm using the libxslt C library, and need to pass in parameters as const char *. I'm wrapping the library in a Qt C++ class, so the parameters are stored in the C++ class are store as QMap<QString, QString>.
My first attempt was simply:
const char *params[32];
int index = 0;
if (m_params.size() > 0) {
QMapIterator<QString, QString> it(m_params);
while (it.hasNext()) {
it.next();
params[index++] = it.key().toLocal8Bit().data();
params[index++] = it.value().toLocal8Bit().data();
}
}
params[index++] = nullptr;
qDebug() << params[0] << params[1]; // 0 0
But I realise that this isn't working because the QByteArray from toLocal8bit goes out of scope almost as soon as I've used it.
I've tried using strcpy - but have the same scope issues:
m_params.insert("some-key", "some-value", "another-key", "another-value");
if (m_params.size() > 0) {
QMapIterator<QString, QString> it(m_params);
while (it.hasNext()) {
it.next();
char buffer[32];
strcpy(buffer, it.key().toLocal8Bit().data());
params[index++] = buffer;
strcpy(buffer, it.value().toLocal8Bit().data());
params[index++] = buffer;
}
}
params[index++] = nullptr;
qDebug() << params[0] << params[1]; // another-value another-value
So now I have a list of params all with the same value.
When I set all the values manually, I get the expected outcomes:
const char *params[32];
int index = 0;
params[index++] = "something";
params[index++] = "something-else";
params[index++] = nullptr;
qDebug() << params[0] << params[1]; // something something-else
This is easy enough - you need to ensure that the buffer for the parameters persists long enough. Do not use fixed-size arrays - you're setting yourself up for a buffer overflow.
class Params {
QByteArray buf;
QVector<const char *> params;
public:
Params() = default;
template <class T> explicit Params(const T& map) {
QVector<int> indices;
indices.reserve(map.size());
params.reserve(map.size()+1);
for (auto it = map.begin(); it != map.end(); ++it) {
indices.push_back(buf.size());
buf.append(it.key().toLocal8Bit());
buf.append('\0');
indices.push_back(buf.size());
buf.append(it.value().toLocal8Bit());
buf.append('\0');
}
for (int index : qAsConst(indices))
params.push_back(buf.constData() + index);
params.push_back(nullptr);
}
operator const char **() const { return const_cast<const char**>(params.data()); }
operator const char *const*() const { return params.data(); }
operator QVector<const char*>() const { return params; }
};
void MyClass::method() const {
Params params{m_params};
...
res = xsltApplyStylesheet(cur, doc, params);
...
}
Related
I am trying to initialize an array of String (the class contains a default constructor and a constructor like this one: String(const char* helper). I also have overloaded operator for <<;
However when I try to do the following, nothing happens :
String suits[4] = {"Hearts", "Clubs", "Diamonds", "Spades"};
std::cout << suits[2];
But this one is okay :
const String suit = "Hearts";
std::cout <<suit;
0
it works the same without the const. I wanted to build myself the string class. About the string class :
class String
{
char* buffer;
int size;
public:
String(const char* helper)
{
size_t sizeH = strlen(helper);
buffer = new char[sizeH];
for (int i = 0; i < sizeH; ++i)
{
buffer[i] = helper[i];
}
buffer[sizeH] = 0;
size = sizeH;
}
String()
{
buffer = nullptr;
size = 0;
}
void sizeOfBuffer()
{
std::cout <<size<<"\n";
}
~String()
{
delete[] buffer;
}
I have a problem about initializing char* a = new char[size]. Here is my code.
class Practice
{
public:
Practice(const char* a);
~Practice();
const char* getString() const;
private:
char* mString;
int mSize;
};
#include "Practice.h"
Practice::Practice(const char * a)
:mSize(0)
,mString(nullptr)
{
while (a[mSize] != '\0')
{
mSize++;
}
mString = new char[mSize];
for (int i = 0; i < mSize; i++)
{
mString[i] = a[i];
}
}
Practice::~Practice()
{
delete[] mString;
}
const char* Practice::getString() const
{
return mString;
}
int main()
{
Practice p("Hello");
std::cout << p.getString() << std::endl;
return 0;
}
I expected the result is Hello.
But the result was like Hello²²²²▌▌▌▌▌▌▌■a%{▌.
I thought I initialized the mString member variable through mString = new char[mSize]. But it was not working the way I thought.
Can anybody enlighten me what's wrong with my code and fix it?
mString is not NUL-terminated.
Your're checking a constructor parameter for \0. But you are not allocating mString to put the same \0 there, and don't copy \0 from a.
So, resulting mString is not properly NULL-terminated and it would be read beyond end.
Reading beyond end of allocated is undefined behavior. In particular case, it is likely that either mString would output until some accidental zero, or crash would occur.
while (a[mSize] != '\0')
{
mSize++;
}
This sets mSize equal to the length of a, excluding the terminating '\0'. You should include the terminator in your copy:
while (a[mSize++])
{
}
or simply:
mSize = strlen(a) + 1;
You are not null-terminating your mString data, but it is expecting to be null-terminated when you pass it to std::cout. Without that terminator, std::cout reads into surrounding memory until it encounters a random null byte (or crashes with a read access error). That is why you are seeing std::cout output random garbage after your data.
You are also not following the Rule of 3/5/0, as you are missing a default constructor, copy and move constructors, and copy and move assignment operators.
Try this:
class Practice
{
public:
Practice(const char* a = nullptr);
Practice(const Practice &src);
Practice(Practice &&src);
~Practice();
Practice& operator=(Practice src);
const char* getString() const;
private:
char* mString;
int mSize;
};
#include "Practice.h"
#include <utility>
Practice::Practice(const char * a)
: mSize(0)
, mString(nullptr)
{
if (a)
{
while (a[mSize] != '\0')
{
++mSize;
}
}
mString = new char[mSize + 1];
for (int i = 0; i < mSize; ++i)
{
mString[i] = a[i];
}
mString[mSize] = '\0';
}
Practice::Practice(const Practice &src)
: mSize(src.mSize)
, mString(nullptr)
{
mString = new char[mSize + 1];
for (int i = 0; i < mSize; ++i)
{
mString[i] = src.mString[i];
}
mString[mSize] = '\0';
}
Practice::Practice(Practice &&src)
: mSize(src.mSize)
, mString(src.mString)
{
src.mString = nullptr;
src.mSize = 0;
}
Practice::~Practice()
{
delete[] mString;
}
Practice& Practice::operator=(Practice src)
{
std::swap(mString, src.mString);
std::swap(mSize, src.mSize);
return *this;
}
const char* Practice::getString() const
{
return mString;
}
#include <iostream>
#include "Practice.h"
int main()
{
Practice p("Hello");
std::cout << p.getString() << std::endl;
return 0;
}
I am new bee for c++ . I got follow error when I override operator+ .
ConsoleApplication1.out: /root/projects/ConsoleApplication1/sdstring.cpp:43: static sdstring::size_t sdstring::strlen(const char*): Assertion `str' failed.
This is my test code!
sdstring sd1(NULL);
cout << "sd1:" << sd1 << endl;
sdstring sd2("sd2");
cout << "sd2:" << sd2 << endl;
sdstring sd3;
cin >> sd3;
cout << "sd3:" << sd3 << endl;
sd3 +=sd2 ;
cout << "sd3:" << sd3 << endl;
sdstring sd4 =sd3+sd1;
cout << "sd4:" << sd2 << endl;
sd1 = sd2 + sd1;
cout << "sd1:" << sd1 << endl;
cout << "sd3==sd2:" << (sd3 == sd2)<<endl;
Error happened in This line .
sdstring sd4 =sd3+sd1;
This is my sdstring.cpp file.
#include "sdstring.h"
#include <assert.h>
sdstring::sdstring(const char *str) {
if (!str) {
datas = new char[1];
datas[0] = '\0';
}
else {
datas = new char[strlen(str)+1];
strcpy(datas, str);
}
}
sdstring::sdstring(const sdstring& str) {
datas = new char[strlen(str.datas) + 1];
strcpy(datas, str.datas);
}
sdstring& sdstring::operator+(const sdstring& str)const {
sdstring result(NULL);
size_t total_size = getlen() + str.getlen();
result.datas = new char[total_size + 1];
strcpy(result.datas, datas);
strcat(result.datas, str.datas);
return result;
}
bool sdstring::operator==(const sdstring& str)const {
return strcmp(datas, str.datas) == 0;
}
sdstring& sdstring::operator=(const sdstring& str) {
if (this == &str)
return *this;
delete[] datas;
datas = new char[str.getlen() + 1];
strcpy(datas, str.datas);
return *this;
}
sdstring::size_t sdstring::strlen(const char* str) {
assert(str);
size_t len = 0;
while ('\0' != *str++)
len++;
return len;
}
char* sdstring::strcpy( char* des, const char* src){
assert(des&& src);
char* temp = des;
while ('\0' != (*des++ = *src++));
return temp;
}
int sdstring::strcmp(const char* fir, const char* sec) {
assert(fir && sec);
while (*fir == *sec)
{
if (*fir == '\0') {
return 0;
}
++fir;
++sec;
}
return *fir - *sec;
}
char* sdstring::strcat(char* des,const char* src) {
char* temp = des;
while ('\0' != *des)
{
des++;
}
while ('\0' != (*des++ = *src++));
return temp;
}
sdstring::~sdstring()
{
if (datas)
{
delete[] datas;
datas = nullptr;
}
}
char& sdstring::operator[](const unsigned int position)const
{
return position < getlen() ? datas[position] : datas[position-1];
}
sdstring& sdstring::operator+=(const sdstring& str)
{
size_t total_size = getlen() + str.getlen();
if (total_size != getlen()) {
char* temp = datas;
datas = new char[total_size + 1];
strcpy(datas,temp);
strcat(datas, str.datas);
delete[] temp;
}
return *this;
}
ostream& operator<<(ostream& os, const sdstring& str)
{
os << str.datas;
return os;
}
istream& operator>>(istream& is, sdstring& str)
{
char* cache = new char[1024];
is >> cache;
delete[]str.datas;
str.datas = new char[sdstring::strlen(cache)];
sdstring::strcpy(str.datas, cache);
delete[]cache;
return is;
}
Who can help me , Thanks for first!
There are several things wrong with your code. However the operator + is wrong in that it is returning a reference to a local variable, which is undefined behavior.
sdstring& sdstring::operator+(const sdstring& str)const
{
sdstring result(NULL);
//..
return result; // Undefined behavior.
}
operator + should be returning a brand new object, not a reference to an object.
sdstring sdstring::operator+(const sdstring& str)const // <-- Note the return value is sdstring
{
sdstring result(NULL);
//..
return result;
}
The other issues with your code:
1) The operator= destroys the memory using delete[] datas; before calling new[] to allocate memory for the new string. If new[] throws an exception, the sdstring object would be corrupted since the data has been destroyed and you can't go back and reset the string with the old data. Use the copy / swap idiom to prevent this from happening.
2) You should store the length of the string in a member variable instead of calling strlen every time you want to know the length of the string. The strlen is slow in that it has to loop to count every single character to determine where the terminating '\0' character is located. Instead of that, just store the length of the string once and keep using that value.
3) Instead of writing your own strlen and strcmp functions, use the library functions strlen and strcmp. Your versions are not optimized, unlike the library versions.
4) operator + can be written in terms of operator +=. operator + should be written very simply as:
sdstring sdstring::operator + (const sdstring& rhs)
{
return sdstring(*this) += rhs;
}
Basically what the title says. I have been trying to write my own string class using only char arrays and, while my code works when I run it in Visual Studio, I have trouble with it when using gcc .The problem seems to be coming when i try to delete in my getData function(can be seen below) The exception I get is:
Exception thrown at 0x6262436B (ucrtbased.dll) in string.exe: 0xC0000005: Access violation reading location 0xCCCCCCBC. occurred
My code :
Header:
#pragma warning(disable:4996)
#ifndef STRING_STRING_H
#define STRING_STRING_H
#include<iostream>
#include<cstring>
#include<fstream>
class String {
private:
char *data; //holds the text
size_t maxSize; //maximum number of chars in data
size_t currentSize; //current number of chars in data
void getData(const char *, size_t maxSize); //sets currentSize to the other char* size and
// copies the content of the other char* to data
public:
String(); //default constructor
~String(); //destructor
String(const String &); //copy-constructor(from String)
String(const char *); //copy-constructor(from char*)
String operator=(const String &); //operator= (from string)
String operator=(const char *); //operator=(from char*)
size_t length() const; //currentSize getter
void addChar(const char); //adds a char to the data array
void getLine(std::ifstream&,const char); // reads line till deliminator and stores it in this string object(all data previously stored is lost)
size_t find(const char*); //searches for text in the string and if found returns the starting position , if not found returns -1;
void print() const; //prints the string object to console
char* toChar() const; //returns a new allocated char pointer with the text inside (must be deleted afterwards)
};
#endif //STRING_STRING_H
cpp:
#include "String.h"
String::String() {
currentSize = 0;
maxSize = 16;
try {
data = new char[maxSize];
data[0] = '\0';
}
catch (std::bad_alloc &) {
std::cerr << "Not enough memory" << std::endl;
throw;
}
}
String::~String() {
delete[] data;
}
size_t String::length() const {
return currentSize;
}
String::String(const String &other) {
this->maxSize = other.maxSize;
getData(other.data, maxSize);
}
String::String(const char *other) {
this->maxSize = strlen(other) *2;
getData(other, maxSize);
}
void String::getData(const char *dataSource, size_t maxSize) {
currentSize = strlen(dataSource);
try {
char *newData = new char[maxSize];
delete[] data;
data = newData;
strcpy(data, dataSource);
}
catch (std::bad_alloc &) {
std::cerr << "Not enough memory" << std::endl;
throw;
}
}
String String::operator=(const String &other) {
if (this != &other) {
maxSize = other.maxSize;
getData(other.data, maxSize);
}
return *this;
}
String String::operator=(const char *other) {
if (this->data != other) {
maxSize = strlen(other) *2;
getData(other, maxSize);
}
return *this;
}
void String::addChar(const char newChar) {
if (maxSize == currentSize+1) {
maxSize *= 2;
getData(this->data, maxSize);
}
data[currentSize++] = newChar;
}
void String::getLine(std::ifstream & is, const char delim='\n')
{
char temp;
while (!is.eof())
{
is.get(temp);
if (temp == delim)
break;
else
addChar(temp);
}
return;
}
size_t String::find(const char * text)
{
size_t currPos=-1;
bool found = 0;
for (size_t i = 0; i < currentSize; i++)
{
if (data[i] == text[0])
{
for (size_t j = i+1; j < currentSize; j++)
{
if (data[j] == text[j - i])
found = 1;
else
{
found = 0;
break;
}
}
if (found == 1)
{
currPos = i;
break;
}
}
}
return currPos;
}
void String::print() const
{
for (size_t i = 0; i < currentSize; i++)
{
std::cout << data[i];
}
std::cout << std::endl;
}
char * String::toChar() const
{
char* text= new char[currentSize+1];
for (size_t i = 0; i < currentSize; i++)
{
text[i] = data[i];
}
text[currentSize + 1] = 0;
return text;
}
Your problem is caused by calling delete [] on uninitialized memory.
In the copy constructor, the data member is not initialized before calling getData(). In getData(), you are using delete [] data;.
You could initialize data to nullptr in the constructors to avoid the problem.
It's always a good idea to initialize all variables to some sensible value before the body of the constructor. E.g. you can implement the copy constructor as:
String::String(const String &other) : currentSize(0),
maxSize(other.maxSize),
data(nullptr)
{
getData(other.data, maxSize);
}
Similarly, implement the constructor from char const* as:
String::String(const char *other) : currentSize(0),
maxSize(strlen(other) *2),
data(nullptr)
{
getData(other, maxSize);
}
I am trying to implement a basic string class in C++. However, I am stuck on the append() function. It would like it to be Hello World, but it results as Hello ÍWorlýýýý««««««««þ:
#define __START namespace lib{
#define __END }
__START
class string
{
public:
string(const char* s)
{
_str = s;
}
const char operator[](int position)
{
return _str[position];
}
void operator=(string s)
{
_str = s.c_str();
}
void append(string s)
{
size_t nlength = (length() + s.length());
char* nstr = new char[nlength];
for (int i = 0; i < length(); ++i)
{
nstr[i] = _str[i];
}
for (int i = length() + 1; i < nlength; ++i)
{
nstr[i] = s[(i - length() - 1)];
}
_str = const_cast<const char*>(nstr);
}
void operator+=(string s)
{
append(s);
}
const char* c_str()
{
return _str;
}
size_t length()
{
return strlen(_str);
}
std::string str()
{
return _str;
}
private:
const char* _str;
};
__END
int main()
{
lib::string s = "Hello ";
s.append("World"); // s += "World";
std::cout << s.c_str();
getchar();
}
There are a lot of errors, not only with append
string(const char* s)
{
_str = s;
}
The constructor is wrong, you should make a copy of s in order to free it later, this way:
~string()
{
delete[] _str; // or free(_str) in case you use malloc/realloc, thanks Fred!
}
Private member variable:
private:
const char* _str;
The internal string should not be const, you should be able to resize it later
const char operator[](int position)
{
return _str[position];
}
You are missing a check: length() > position
void operator=(string s)
{
_str = s.c_str();
}
You are not modifying s, it should be const string& s
You are also not copying s.c_str() which means that now s and this are sharing the same internal buffer
void append(string s) // s should be a const reference too
{
size_t nlength = (length() + s.length());
char* nstr = new char[nlength];
for (int i = 0; i < length(); ++i)
{
nstr[i] = _str[i];
}
for (int i = length() + 1; i < nlength; ++i)
{
nstr[i] = s[(i - length() - 1)];
}
_str = const_cast<const char*>(nstr);
}
Should be easier to write in terms of realloc:
void append(string s)
{
int start = length();
_str = realloc(_str, length() + s.length());
for (int i = 0; i < s.length(); i++) {
_str[start+i] = s[i];
}
}
If you want to stick to new its OK, but you must free _str before assigning it to the new one.
The following operators should be const:
const char* c_str() const;
size_t length() const;
std::string str();
Update: Options for the constructor:
// option one (use delete[] to cleanup _str)
string(const char* s) {
int n = strlen(s);
_str = new char[n+1];
memcpy(_str, s, n+1); // s is NULL terminated
}
// option two (use free() to cleanup _str)
string(const char* s) {
int n = strlen(s);
_str = (char*)malloc(n+1);
memcpy(_str, s, n+1); // s is NULL terminated
}
// option 3: rely on append taking a char* argument
string(const char *s) : _str(NULL) {
append(s, strlen(s));
}
..
void append(const string& s) {
append(s.c_str(), s.length())
}
void append(const char *s, int len) {
int start = _str ? length() : 0;
_str = realloc(_str, start + len);
for (int i = 0; i < len; i++) {
_str[start+i] = s[i];
}
}
Update 2: It will be better to use size_t or unsigned int instead of plain int because the size is always greater than or equal to zero.
There are tons of problems with your code, so let's do this step by step.
First, you don't need your preprocessor magic for the namespace, but just a basic namespace mynamespace{}.
Secondly, it is ideal to create a basic_string class, so that it can be used with different character types. char / wchar_t, e.t.c.
Problems with your class:
1) private: const char *_str;. The pointer will be modified, so the const is useless.
2) There are no typedefs. You need them if you are attempting to re-implement a STL class. (Explained in example)
3) Use an allocator. This way you can construct, and destroy elements, allocate, and deallocate memory. You will be certain to keep your memory a lot safer this way.
4) Strings must be null terminated. That means an extra '\0' at the end, meaning you will have to allocate an extra byte for that. Strings are null terminated, because it is a way of telling the code to stop reading the string.
5) You are assigning to a string which has not been allocated. _str = s.c_str(); could easily crash, depending on your compiler, because you are writing to non-allocated memory.
6) Use const references, rather than normal types for your parameters (string = const string &). You also need this for your copy constructor basic_string(const _Myt &).
I still may not have highlighted all of the problems
Example basic_string class
template < typename _Elem, typename _Traits = std::char_traits<_Elem>, typename _Alloc = std::allocator<_Elem> > class basic_string
{
public:
typedef basic_string<_Elem, _Traits, _Alloc> _Myt;
typedef _Elem value_type;
typedef _Traits traits_type;
typedef _Alloc allocator_type;
typedef value_type *pointer;
typedef const value_type *const_pointer;
typedef value_type *iterator;
typedef const value_type *const_iterator;
typedef value_type &reference;
typedef const value_type &const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
basic_string()
{
__data = _Alloc().allocate(1);
_Alloc().construct(&__data[0], '\0');
}
basic_string(const_pointer _Init)
{
int count = 0;
__data = _Alloc().allocate(_Traits::length(_Init) + 1);
for (const_iterator i = &_Init[0]; i != &_Init[_Traits::length(_Init)]; ++i, ++count)
{
_Alloc().construct(&__data[count], *i);
}
_Alloc().construct(&__data[_Traits::length(_Init)], '\0');
}
basic_string(const _Myt &_Init)
{
if (this != &_Init)
{
int count = 0;
__data = _Alloc().allocate(_Traits::length(_Init.__data) + 1);
for (const_iterator i = &_Init.__data[0]; i != &_Init.__data[_Traits::length(_Init.__data)]; ++i, ++count)
{
_Alloc().construct(&__data[count], *i);
}
_Alloc().construct(&__data[_Traits::length(_Init.__data)], '\0');
}
else
{
__data = _Alloc().allocate(1);
_Alloc().construct(&__data[0], '\0');
}
}
~basic_string()
{
if (__data)
{
size_type tmp = size();
for (iterator i = begin(); i != end(); ++i)
{
_Alloc().destroy(i);
}
_Alloc().deallocate(__data, tmp);
}
}
_Myt &assign(const_pointer _Rhs)
{
int count = 0;
reserve(_Traits::length(_Rhs) + 1);
for (const_iterator i = &_Rhs[0]; i != &_Rhs[_Traits::length(_Rhs)]; ++i, ++count)
{
_Alloc().construct(&__data[count], *i);
}
_Alloc().construct(&__data[_Traits::length(_Rhs)], '\0');
return *this;
}
_Myt &operator=(const_pointer _Rhs)
{
return assign(_Rhs);
}
_Myt &append(const_pointer _Rhs)
{
int count = size();
reserve(size() + _Traits::length(_Rhs) + 1);
for (const_iterator i = &_Rhs[0]; i != &_Rhs[_Traits::length(_Rhs)]; ++i, ++count)
{
_Alloc().construct(&__data[count], *i);
}
_Alloc().construct(&__data[count], '\0');
return *this;
}
_Myt &operator+=(const_pointer _Rhs)
{
return append(_Rhs);
}
iterator begin()
{
return &__data[0];
}
iterator end()
{
return &__data[size()];
}
size_type size()
{
return _Traits::length(__data);
}
_Myt &swap(basic_string<_Elem> &_Rhs)
{
std::swap(__data, _Rhs.__data);
return *this;
}
void reserve(size_type _Size)
{
int count = 0;
if (_Size < size())
{
return;
}
pointer buf = _Alloc().allocate(_Size);
for (iterator i = begin(); i != end(); ++i, ++count)
{
_Alloc().construct(&buf[count], *i);
}
std::swap(__data, buf);
for (iterator i = &buf[0]; i != &buf[_Traits::length(buf)]; ++i)
{
_Alloc().destroy(i);
}
_Alloc().deallocate(buf, _Traits::length(buf));
}
operator const_pointer()
{
return __data;
}
operator pointer()
{
return __data;
}
template < typename _Traits1, typename _Alloc1 > friend std::basic_ostream<_Elem> &operator<<(std::basic_ostream<_Elem> &_Stream, basic_string<_Elem, _Traits1, _Alloc1> &_Str)
{
return _Stream << _Str.c_str();
}
const_pointer data() const
{
return __data;
}
const_pointer c_str() const
{
return __data;
}
private:
pointer __data;
};
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
Of course, there is still a bit missing, but I'm sure you can implement that with a little online help.
First of all, your most critical problem is in char* nstr = new char[nlength];.
You must change it to char* nstr = new char[nlength+1];.
Then, in function append, after the two for loops, set nstr[nlength] = 0;
Second, for better performance (as well as correct coding), you probably need to change string s to const string& s in the following functions:
void operator=(string s)
void append(string s)
void operator+=(string s)
You have an off-by-one error in the second loop; the second string needs to be copied to length(), immediately after the end of the first:
for (int i = length(); i < nlength; ++i)
{
nstr[i] = s[i - length()];
}
You'll also need to allocate one more byte to put a null terminator on the end.
Note that you don't need that scary-looking cast to add const to the pointer, since that's a perfectly safe thing to do. const_cast is only needed to remove qualifiers. You might also want to fix the memory leak and, for bonus points, cache the length so you don't have to read the entire string every time you want it.
for (int i = length() + 1; i < nlength; ++i)
{
nstr[i] = s[(i - length() - 1)];
}
You first copy chars up to length()-1 and then start back at length() + 1, so you skip a char and there could be anything in there after allocation(unless you do a memset beforehand).
Then you need to terminate your string with a null character(\0) so that the std::string that gets constructed on str() method return knows when to stop reading chars.