• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Nie mogę zwrócić obiektu,błąd z konstruktorem explicit

Object Storage Arubacloud
0 głosów
210 wizyt
pytanie zadane 10 grudnia 2019 w C i C++ przez DamianW Bywalec (2,080 p.)

Witam , mam problem ze zwróceniem obiektu klasy Fraction w przeciążeniu operatora + . Chcę zadeklarować konstruktory jako explicit ,by uniknąć niejawnych konwersji. Jednak przy próbie zwrócenia obiektu kompilator zgłasza błąd kompilacji :

...(43,37): error C2440: "return": nie można konwertować z "enbr::Fraction" na "enbr::Fraction"
...(43,37): message : Konstruktor dla class "enbr::Fraction" jest zadeklarowany jako "explicit"

Przecież zadeklarowałem i zdefiniowałem konstruktor kopiujący.Co może być nie tak ?

/// plik.h
namespace enbr {
	
	class Fraction {
	friend std::ostream& operator<<(std::ostream&, Fraction&);
	private:
		int numerator;
		int denominator;
	private:
		void sgn();
		void shortFrac();
		void correction();
	public:
		Fraction();
		explicit Fraction(const int,const int = 1);
		explicit Fraction(const Fraction&);
		explicit Fraction(Fraction&&) noexcept;
		~Fraction() = default;
	public:
		//Fraction operator= (const Fraction&); w toku 
		Fraction operator+ (const Fraction&);
		
	};
}
void enbr::Fraction::sgn() {
	if ((this->numerator > 0) && (this->denominator < 0)) {
		numerator *= -1; denominator *= -1;}
	else if ((this->numerator < 0) && (this->denominator < 0)) {
		numerator *= -1; denominator *= -1;}
}

void enbr::Fraction::shortFrac() {
	int guard{1};
	if (abs(this->denominator) <= abs(this->numerator))
		guard = abs(this->denominator);
	else guard = abs(this->numerator);
	for (guard; guard > 1; guard--) {
		if ((this->numerator % guard == 0) && (this->denominator % guard == 0)) {
			this->numerator /= guard; this->denominator /= guard;}
	}
}

void enbr::Fraction::correction() {
	sgn();
	shortFrac();
}

enbr::Fraction::Fraction() : numerator{0}, denominator{1}{}

enbr::Fraction::Fraction(const int num, const int den) : numerator{ num }, denominator{ den }{
	correction();
	if (den == 0)
		throw err::ZeroDenominator{"ltr::Fraction::Fraction","usun zero z mianownika"};
}

enbr::Fraction::Fraction(const Fraction& frc)
	: numerator{ frc.numerator }, denominator{ frc.denominator } {}

enbr::Fraction::Fraction(Fraction&& frc) noexcept
	: numerator{ frc.numerator }, denominator{ frc.denominator } {}

enbr::Fraction enbr::Fraction::operator+ (const Fraction& frac) {
	int new_num{ this->numerator * frac.denominator + this->denominator * frac.numerator};
	int new_den{ this->denominator * frac.denominator };
	return Fraction{ new_num, new_den }; // <- tu występuje błąd
}

 

2 odpowiedzi

0 głosów
odpowiedź 11 grudnia 2019 przez mokrowski Mędrzec (155,460 p.)
wybrane 13 grudnia 2019 przez DamianW
 
Najlepsza
Najprościej:

W linii 41 implementacji, masz zwrócenie przez kopię. Wiadomo że będzie tu wykorzystane RVO, niemniej jednak kompilator ma wymaganie że powinna być możliwość wykonania takiej kopii. Stąd w pliku *.h, przed konstruktorem kopiującym usuń explicit.
komentarz 11 grudnia 2019 przez DamianW Bywalec (2,080 p.)
No dobrze, mam pytanko. Jeżeli funkcja zwraca obiekt jakiegokolwiek typu poprzez wartość to zawsze jest to rvalue ?
1
komentarz 11 grudnia 2019 przez mokrowski Mędrzec (155,460 p.)
Oczywiście że nie. Zależy co (jak alokowane) zwraca i w jaki sposób zwraca. Sprecyzuj pytanie albo lepiej określi jakie masz wyzwanie :)
komentarz 11 grudnia 2019 przez DamianW Bywalec (2,080 p.)

No dobrze, załóżmy ,że mam przeciążony operator+. Chciałbym uniknąć utworzenia obiektu w miejscu wywołania operatora+ i jeszcze raz skopiowania go do lewostronnego argumentu operatora=, ze względów wydajnościowych.Np. coś takiego: 

template<class T>
enbr::AnyVector<T> enbr::AnyVector<T>::operator+ (const AnyVector<T>& vec) {
	//if ((this->size != vec.size) || (this->element.size() != //vec.element.size()))
		//throw err::IncompatibleDims{ "enbr::AnyVector<T> //enbr::AnyVector<T>::operator+","sprawdz wymiary wektorow" };
	enbr::AnyVector<T> new_vec{};
	for (int i = 0; i < this->size;i++) 
		new_vec.element.push_back(this->element[i] + vec.element[i]);
	new_vec.size = this->size;
	return new_vec;
}

 

1
komentarz 12 grudnia 2019 przez mokrowski Mędrzec (155,460 p.)

Chciałbym uniknąć utworzenia obiektu w miejscu wywołania operatora+...

W funkcji która zwraca dane "przez kopię", istnieje obowiązek implementowania optymalizacji RVO. Oznacza to że dane na których operuje funkcja, rezydują w przestrzeni stosu ciała funkcji wywołującej. Nie ma więc wykonywanej kopii danych. Niemniej jednak z tego powodu że składania sugeruje użycie takiej kopii wymagane jest implementowanie semantyki kopiowania (czyli np. konstruktora kopiującego oraz operatora przypisania) nawet jeśli nie będą użyte.

i jeszcze raz skopiowania go do lewostronnego argumentu operatora=

Tu także jeśli masz trywialne zastosowanie np typu:

Klasa cls = funkcja_budujaca_klase();

lub...

Klasa cls = Klasa();

... stosowana jest optymalizacja Copy elision ( https://en.cppreference.com/w/cpp/language/copy_elision ). To oznacza że kompilator także orientuje się że nie ma powodu wykonywania operacji kopiowania i zwykła konstrukcja wystarcza.

Czyli... nie wyręczaj kompilatora :)

0 głosów
odpowiedź 11 grudnia 2019 przez criss Mędrzec (172,590 p.)

Po co konstruktor kopiujący i przenoszący są explicit? Najprościej by było usunąć explicit, IMO bez sensu i tylko utrudnia. Drugi sposób: być może zadziała Fraction(Fraction{ new_num, new_den }), ale ciężko powiedzieć. Możliwe, że zadziała tylko z c++17 (ze wzgl na copy elision) a w niższych już nie..

Podobne pytania

0 głosów
3 odpowiedzi 3,827 wizyt
pytanie zadane 29 listopada 2015 w C i C++ przez Patryk Krajewski Nałogowiec (26,170 p.)
0 głosów
1 odpowiedź 265 wizyt
pytanie zadane 10 czerwca 2018 w C i C++ przez WhizzKid Początkujący (400 p.)
0 głosów
0 odpowiedzi 215 wizyt

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...