SmartPtr
With Move Semantics¶
Overview¶
Continue From
SmartPtr
With Explicitmove()
Define “Return From Function Moves” requirement
Starting Point¶
#include "sensors.h"
#include <gtest/gtest.h>
template <typename T> class SmartPtr
{
public:
SmartPtr() : _p(nullptr) {}
SmartPtr(T* p) : _p(p) {}
~SmartPtr() { delete _p; }
SmartPtr(const SmartPtr&) = delete;
SmartPtr& operator=(const SmartPtr&) = delete;
T* operator->() { return _p; }
const T* operator->() const { return _p; }
T& operator*() { return *_p; }
const T& operator*() const { return *_p; }
const T* get() const { return _p; }
void move(SmartPtr& other)
{
delete _p;
_p = other._p;
other._p = nullptr;
}
private:
T* _p;
};
TEST(handwritten_suite, explicit_move)
{
SmartPtr<Sensor> s1{new ConstantSensor{20}};
SmartPtr<Sensor> s2;
s2.move(s1);
ASSERT_EQ(s1.get(), nullptr);
ASSERT_DOUBLE_EQ(s2->get_temperature(), 20);
}
Return SmartPtr
Object From Function¶
SmartPtr<Sensor> create_constant_sensor(double temperature)
{
SmartPtr<Sensor> sp{new ConstantSensor{36.5}};
return sp;
}
SmartPtr
has copydelete
d⟶ error
But: compiler can prove that
sp
is unused afterreturn
⟶ Implement move constructor
#include "sensors.h"
#include <gtest/gtest.h>
template <typename T> class SmartPtr
{
public:
SmartPtr() : _p(nullptr) {}
SmartPtr(T* p) : _p(p) {}
~SmartPtr() { delete _p; }
SmartPtr(SmartPtr&& from)
{
delete _p;
// think about atomic-exchange though, maybe
_p = from._p;
from._p = nullptr;
}
SmartPtr(const SmartPtr&) = delete;
SmartPtr& operator=(const SmartPtr&) = delete;
T* operator->() { return _p; }
const T* operator->() const { return _p; }
T& operator*() { return *_p; }
const T& operator*() const { return *_p; }
const T* get() const { return _p; }
private:
T* _p;
};
SmartPtr<Sensor> create_constant_sensor(double temperature)
{
SmartPtr<Sensor> sp{new ConstantSensor{36.5}};
return sp;
}
TEST(handwritten_suite, return_by_copy)
{
auto a_sensor = create_constant_sensor(36.5);
ASSERT_FLOAT_EQ(a_sensor->get_temperature(), 36.5);
}
Assign SmartPtr
Object ⟶ Moved¶
TEST(handwritten_suite, assignment)
{
SmartPtr<Sensor> a_sensor{new ConstantSensor{36.5}};
SmartPtr<Sensor> another_sensor;
another_sensor = a_sensor;
}
SmartPtr
has assignment operatordelete
d⟶ error
Attempt #1: implement move assignment
Put correct SmartPtr
implementation (see below), but fail to
std::move()
the assignee ⟶ error
Attempt #2: move
#include "sensors.h"
#include <gtest/gtest.h>
template <typename T> class SmartPtr
{
public:
SmartPtr() : _p(nullptr) {}
SmartPtr(T* p) : _p(p) {}
~SmartPtr() { delete _p; }
SmartPtr(SmartPtr&& from)
{
_p = from._p;
from._p = nullptr;
}
SmartPtr& operator=(SmartPtr&& from)
{
// much like self-assignment check, but more dubious
if (this != &from) {
delete _p;
_p = from._p;
from._p = nullptr;
}
return *this;
}
SmartPtr(const SmartPtr&) = delete;
SmartPtr& operator=(const SmartPtr&) = delete;
T* operator->() { return _p; }
const T* operator->() const { return _p; }
T& operator*() { return *_p; }
const T& operator*() const { return *_p; }
const T* get() const { return _p; }
private:
T* _p;
};
TEST(handwritten_suite, assignment)
{
SmartPtr<Sensor> a_sensor{new ConstantSensor{36.5}};
SmartPtr<Sensor> another_sensor;
another_sensor = std::move(a_sensor);
ASSERT_EQ(a_sensor.get(), nullptr);
}