Konstruktor przenoszący psujący operator+; klasa String

0

Cześć, przerabiam w ramach ćwiczenia klasę string:

Mam problem z String operator+(const String & st1,const String & st2); . Bez dodanego konstruktora przenoszącego działa przeciążenie operatora poprawnie, natomiast z konstruktorem następuje błąd. Szczególnie nie rozumiem w jakim momencie przenoszenie psuje operator+, ani jak to się dzieje :(
Invalid address specified to RtlValidateHeap coś ze zwolnieniem się dzieje...

Header.h

#ifndef HEADER_H_
#define HEADER_H_
#include <iostream>
#include <string.h>
#include <cctype>
using std::ostream;
using std::istream;

class String
{
private:
	char *data;				// wskaźnik ciągu
	int len;                // długość ciągu
	
public:
	String();						// konstruktor domyślny
	String(const char * s);			// konstruktor kopiujący
	String(const String & st);		// konstruktor kopiujący

	String(String&& rhs);			// konstruktor przenoszący
	
	~String();                // destruktor

	String & operator=(const String & st);
	String & operator=(const char * s);
	friend ostream & operator<<(ostream & os, const String & st);
	friend istream & operator>>(istream & is, String & st);

	auto getData() const { return data; }
	auto setData(const String & st1, const String & st2);
	auto getLength() const { return len; }
	auto setLenght(const String & st1, const String & st2) { len = st1.len + st2.len; }

};

String operator+(const String & st1,const String & st2);

#endif // !HEADER_H_

Def.cpp

#include <cstring>   
#include "header.h"  

using std::cin;
using std::cout;

String::String(const char * s):         // konstruje obiekt String z ciągu C
	len(std::strlen(s))					// ustawienie długości ciągu
{
	data = new char[len+1];				// przydział pamięci
	strcpy_s(data,len+1 ,s);			// inicjalizacja wskaźnika ciągu								
}

String::String()                        // konstruktor domyślny
{
	len = 1;
	data = new char[1];
	data[0] = '\0';                      // domyślny ciąg obiektów klasy
}

String::String(const String & st):
	len(st.getLength())							// ta sama długość ciągu
{									
	data = new char[len + 1];				 // przydział pamięci
	strcpy_s(data, len + 1, st.getData());   // skopiowanie ciągu
}

String::String(String&& rhs):
	len(std::move(rhs.len)),
	data(std::move(rhs.data))
{
}

String::~String()                        // destruktor 
{										 
	delete[] data;                      
}

// przypisywanie obiektu klasy String do innego obiektu tej klasy
String & String::operator=(const String & st)
{
	if (this == &st)
		return *this;
	delete[] data;
	len = st.len;
	data = new char[len + 1];
	strcpy_s(data, len + 1, st.getData());
	return *this;
}

// przypisywanie ciągu C do obiektu klasy String
String & String::operator=(const char * s)
{
	delete[] data;
	len = std::strlen(s);
	data = new char[len + 1];
	strcpy_s(data, len + 1, s);
	return *this;
}

// wyprowadzenie ciągu na wyjście
ostream & operator<<(ostream & os, const String & st)
{
	os << st.data;
	return os;
}

// wczytywanie ciągu z wejścia (uproszczone)
istream & operator>>(istream & is, String & st)
{
	char temp[String::CINLIM];
	is.get(temp, String::CINLIM);
	if (is)
		st = temp;
	while (is && is.get() != '\n')
		continue;
	return is;
}

auto String::setData(const String & st1, const String & st2)
{
	data = new char[getLength() + 1];
	strcpy_s(data, getLength() + 1, st1.getData());              //tutaj wywala wyjątek
	strcat_s(data, getLength() + 1, st2.getData());                
}

String operator+(const String & st1, const String & st2)                  
{
	String temp;
	temp.setLenght(st1, st2);
	temp.setData(st1, st2);
	return temp;
}

main.cpp

#include <iostream>
#include "header.h"

int main()
{
	using std::cout;
	using std::cin;
	using std::endl;

	const char* src = "Make the test";

	cout << endl<<"String(const char * s);	"<<endl;
	String test1=String(src);
	cout << test1.getData()<<endl;

	cout << endl<<"String(const String & st);"<<endl;
	String test2(test1);
	cout << test2.getData()<<endl;

	cout << endl << "const String operator+(const String & st1, const String & st2);" << endl;
	String test3= "Let's do it!!! " + test1 + test2 + " Make it!!!";
	cout << test3.getData() << endl;
	
	cout << endl << "String(String&& rhs);" << endl;
	String test4(std::move(test1));
	cout << test4.getData() << endl;
	
	system("pause");
	return 0;
}

Byłbym bardzo wdzięczny za wszelkie uwagi ;)

1

Nie ustawiasz rhs.data na nullptr, więc masz double delete.

0

Dzięki wielkie za szybką odpowiedź!

0
 String::String(String&& rhs):
    len(std::move(rhs.len)),
    data(std::move(rhs.data))
{
}

move na int i char* nie ma specjalnie sensu – nie robi tu nic ponad zwykłe przypisanie wartości len(rhs.len)

0
Azarien napisał(a):
 String::String(String&& rhs):
    len(std::move(rhs.len)),
    data(std::move(rhs.data))
{
}

move na int i char* nie ma specjalnie sensu – nie robi tu nic ponad zwykłe przypisanie wartości len(rhs.len)

Wow serio, a to nie wiedziałem myślałem, że zostanie wywołana operacja kopiowania bez move ;) ale z drugiej strony przecież mamy konstruktor przenoszący, który ze swojej natury nam to zapewnia ;)

Dziękuje za uwagę ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1