operator= не вызывается при присваивании. C++
Я уже попробовал приактически всё, чтобы оператор присваивания вызывался, но этого не происходит. Вот код: Shared.hpp:
#pragma once
namespace atl::util {
template <class T>
class shared {
private:
void _delete() {
if (this->m_count == nullptr)
return;
(*this->m_count)--;
if (*this->m_count == 0) {
if (this->m_value != nullptr)
delete this->m_value;
delete this->m_count;
}
}
protected:
T* m_value;
size_t* m_count;
public:
shared() : m_value(nullptr), m_count(new size_t(0)) {}
shared(T* _value, size_t* _count = new size_t(0)) : m_value(_value), m_count(_count) {
if (m_value != nullptr)
(*this->m_count)++;
}
shared(const shared& _another) :
m_value(_another.m_value), m_count(_another.m_count) {
if (this->m_value != nullptr)
(*this->m_count)++;
}
shared(shared&& _what) noexcept :
m_value(_what.m_value), m_count(_what.m_count) {
_what.m_value = nullptr;
_what.m_count = nullptr;
}
~shared() {
this->_delete();
}
static shared <T> create(T* _value, size_t* _count = new size_t(0)) {
return shared <T>(_value, _count);
}
shared& operator=(const shared& _another);
shared& operator=(shared&& _what) noexcept;
T* raw() const {
return this->m_value;
}
T* operator->() const {
return this->raw();
}
T& get() const {
return *this->m_value;
}
T& operator*() const {
return this->get();
}
size_t count() const {
return *this->m_count;
}
};
template <class T>
shared <T>& shared <T>::operator=(const shared <T>& _another) {
if (this == &_another)
return *this;
std::cout << "shared <T>::operator= called!\n";
this->_delete();
this->m_value = _another.m_value;
this->m_count = _another.m_count;
if (this->m_value != nullptr)
(*this->m_count)++;
return *this;
}
template <class T>
shared <T>& shared <T>::operator=(shared <T>&& _what) noexcept {
this->_delete();
this->m_value = _what.m_value;
this->m_count = _what.m_count;
_what.m_value = nullptr;
_what.m_count = nullptr;
return *this;
}
//TODO: const and reinterpreted cast
template <class T, class U>
shared <T> static_pointer_cast(const shared <U>& _object) noexcept {
return shared(static_cast <T*>(_object.raw()));
}
template <class T, class U>
shared <T> dynamic_pointer_cast(shared <U>& _object) noexcept {
T* temp = dynamic_cast <T*>(_object.raw());
if (temp)
return shared <T>(temp);
else
return shared <T>();
}
}
main.cpp:
#include <iostream>
#include <atl/util/Shared.hpp>
using namespace atl::util;
class A {
public:
virtual void print(char def = '\n') const {
std::cout << "A" << def;
}
};
class B : virtual public A {
public:
void print(char def = '\n') const final override {
A::print('-');
std::cout << "B" << def;
}
};
int main() {
shared <B> b = shared <B>(new B());
shared <A> a = dynamic_pointer_cast <A>(b);
a->print();
return 0;
}
Куда и как нужно вставить метод присваивания, чтобы он вызывался и выводил в консоль сообщение (которое сделано как костыль, просто чтобы проверить)?
Заранее спасибо за помощь и ответы.
Ответы (1 шт):
Ну, Вы честно вызываете 2 раза конструктор копирования, вместо оператора присваивания. Соответственно, оператор присваивания и не вызывается (вместо него срабатывает конструктор копирования):
shared <B> b = shared <B>(new B()); // Вызывается shared(const shared&). а не operator=
shared <A> a = dynamic_pointer_cast <A>(b); // Тоже вызывается shared(const shared&). а не operator=
Компилятор делает в точности то, о чём Вы его и попросили.
Если Вам нужен именно оператор присваивания, то, попробуйте следующее:
- конструктор копирования (и перемещения) объявить или =delete, или explicit, т.е.:
explicit shared(const shared& _another) :
m_value(_another.m_value), m_count(_another.m_count) {
if (this->m_value != nullptr)
(*this->m_count)++;
}
explicit shared(shared&& _what) noexcept :
m_value(_what.m_value), m_count(_what.m_count) {
_what.m_value = nullptr;
_what.m_count = nullptr;
}
Или, если конструкторы Вам не нужны, можно их "убить" (в C++11 и выше; или поместить в секцию private, если C++98/03):
shared(const shared& _another) = delete;
shared(shared&& _what) noexcept = delete;
- Если после п.1. компилятор не выдаст Вам ошибку на Ваш вот этот код:
shared <B> b = shared <B>(new B());
shared <A> a = dynamic_pointer_cast <A>(b);
(А он должен, после п.1. выдать вам, что - в зависимости от того, что Вы выберете и сделаете в п.1, сообщить, что так делать нельзя, т.к. (любой из вариантов):
- Конструктор копирования объявлен explicit, следовательно его надо вызывать явно, т.е. так:
shared <B> b(new B());
shared <A> a(dynamic_pointer_cast <A>(b));
- Конструктор копирования, объявленный =delete, удалён и его вызывать нельзя
- Конструктор копирования объявлен с модификатором доступа private и его вызывать нельзя
Соответственно, компилятор заставит Вас написать правильный код, в котором точно будет вызываться оператор присваивания, т.е. такой код:
shared <B> b;//1) Сконструировали b и a
shared <A> a;
b = new B(); //2) Присваиваем b и a соответствующие значения
a = dynamic_pointer_cast <A>(b);
По логике же Вашего кода в вопросе, оператор присваивания должен был бы вызваться ещё ДО срабатывания конструктора (но по правилам C++ объект сначала конструируется и лишь потом можно вызывать его методы и операторы).