Skip to main content
add reference
Source Link

Personally I think so.have the same thought present in Martin York' answer:

  • Private Variables
  • Public
    • Constuctor / Destructor
    • Copy Semantics
    • Move Semantics
    • Swap
    • Other Public Interface
    • Friends
  • Private
    • Methods as appropriate

When reading the code I want to know the members so I can verify that the constructors initialize them all, as a result I usually put them first. But other people prefer to put all private stuff at the bottom.

Personally I think so.

* Private Variables
* Public
    * Constuctor / Destructor
    * Copy Semantics
    * Move Semantics
    * Swap
    * Other Public Interface
    * Friends
* Private
    * Methods as appropriate

When reading the code I want to know the members so I can verify that the constructors initialize them all, as a result I usually put them first. But other people prefer to put all private stuff at the bottom.
I have the same thought present in @Martin York' answer:

unique_ptr(unique_ptr<T>&& uptr) noexcept
                                   //^^^^^^^^
        
unique_ptr<T>& operator=(unique_ptr<T>&& uptr) noexcept
                                                  //^^^^^^^^
The move operators should be marked as noexcept.

When used with standard containers this will enable certain optimizations. This is because if the move is noexcept then certain operations can be guaranteed to work and thus provide the strong exception guarantee.

The move operators should be marked as noexcept.

When used with standard containers this will enable certain optimizations. This is because if the move is noexcept then certain operations can be guaranteed to work and thus provide the strong exception guarantee.

Personally I think so.

  • Private Variables
  • Public
    • Constuctor / Destructor
    • Copy Semantics
    • Move Semantics
    • Swap
    • Other Public Interface
    • Friends
  • Private
    • Methods as appropriate

When reading the code I want to know the members so I can verify that the constructors initialize them all, as a result I usually put them first. But other people prefer to put all private stuff at the bottom.

unique_ptr(unique_ptr<T>&& uptr) noexcept
                               //^^^^^^^^
    
unique_ptr<T>& operator=(unique_ptr<T>&& uptr) noexcept
                                              //^^^^^^^^

The move operators should be marked as noexcept.

When used with standard containers this will enable certain optimizations. This is because if the move is noexcept then certain operations can be guaranteed to work and thus provide the strong exception guarantee.

I have the same thought present in Martin York' answer:

Personally I think so.

* Private Variables
* Public
    * Constuctor / Destructor
    * Copy Semantics
    * Move Semantics
    * Swap
    * Other Public Interface
    * Friends
* Private
    * Methods as appropriate

When reading the code I want to know the members so I can verify that the constructors initialize them all, as a result I usually put them first. But other people prefer to put all private stuff at the bottom.
I have the same thought present in @Martin York' answer:

unique_ptr(unique_ptr<T>&& uptr) noexcept
                                   //^^^^^^^^
        
unique_ptr<T>& operator=(unique_ptr<T>&& uptr) noexcept
                                                  //^^^^^^^^
The move operators should be marked as noexcept.

When used with standard containers this will enable certain optimizations. This is because if the move is noexcept then certain operations can be guaranteed to work and thus provide the strong exception guarantee.
deleted 56 characters in body
Source Link
#include <iostream>

using namespace std;

template<typename T>
class base_ptr {
private:
    using type = remove_extent_t<T>;

protected:
    type* ptr = nullptr;

public:
    base_ptr(){};
 
    base_ptr(const base_ptr<T>& other) = delete;

    base_ptr(base_ptr<T>&& other) noexcept
    : ptr(other.ptr) {
       other.ptr = nullptr;
    }

    type* release(){
       type* tmp = ptr;
       ptr = nullptr;
       return tmp;
    }

    void reset(){
       if(ptr != nullptr){
           if(is_array_v<T>)
               delete[] ptr;
            else
               delete ptr;
       }
       
       ptr = nullptr;
    }

    void reset(type* item) noexcept {
       reset();

       ptr = item;
    }

    void swap(base_ptr<T> &other) noexcept {
       type* tmp = ptr;

       ptr = other.ptr;
      
       other.ptr = tmp;
    }

    operator bool(){
       return ptr;
    }

    type* get(){
        return ptr;
    }

    base_ptr<T>& operator=(base_ptr<T>&& other) noexcept {
       if (this == &other) return *this;
      
       reset();
       ptr = other.ptr;
       other.ptr = nullptr;
      
       return *this;
    }
};

template <typename T>
class unique_ptr : public base_ptr<T> {
public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T>&& other) 
    : base_ptr<T>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T>::ptr = ptr;
    }

    unique_ptr<T>& operator=(unique_ptr<T>&& other){
       base_ptr<T>::operator=( move(other) );

       return *this;
    }

    T* operator->() const {
       return base_ptr<T>::ptr;
    }

    T& operator*() const {
       return *base_ptr<T>::ptr;
    }

    ~unique_ptr(){
       base_ptr<T>::reset();
    }
};

template <typename T>
class unique_ptr<T[]> : public base_ptr<T[]> {
public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T[]>&& other) 
    : base_ptr<T[]>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T[]>::ptr = ptr;
    }

    unique_ptr<T[]>& operator=(unique_ptr<T[]>&& other){
       base_ptr<T[]>::operator=( move(other) );

       return *this;
    }

    T& operator[](int pos) const {
       return base_ptr<T[]>::ptr[pos];
    }

    ~unique_ptr(){
       base_ptr<T[]>::reset();
    }
};

template <class T, class ...Args>
enable_if_t<!is_array_v<T>, unique_ptr<T>>
make_unique(Args&& ...args)
{
   return unique_ptr<T>(new T(forward<Args>(args)...));
};

template <class T>
enable_if_t<is_array_v<T>, unique_ptr<T>>
make_unique(int size)
{
   using type = remove_extent_t<T>;
   return unique_ptr<T>(new type[size]);
};

int main() {
    unique_ptr<int> a (new int(1));
  
    unique_ptr<int> b;

    b.swap(a);

    b = make_unique<int>(2);

    b.reset();
  
    cout << "End" << endl;
  
    return 0;
}
#include <iostream>

using namespace std;

template<typename T>
class base_ptr {
private:
    using type = remove_extent_t<T>;

protected:
    type* ptr = nullptr;

public:
    base_ptr(){};
 
    base_ptr(const base_ptr<T>& other) = delete;

    base_ptr(base_ptr<T>&& other) noexcept
    : ptr(other.ptr) {
       other.ptr = nullptr;
    }

    type* release(){
       type* tmp = ptr;
       ptr = nullptr;
       return tmp;
    }

    void reset(){
       if(ptr != nullptr){
           if(is_array_v<T>)
               delete[] ptr;
            else
               delete ptr;
       }
       
       ptr = nullptr;
    }

    void reset(type* item) noexcept {
       reset();

       ptr = item;
    }

    void swap(base_ptr<T> &other) noexcept {
       type* tmp = ptr;

       ptr = other.ptr;
      
       other.ptr = tmp;
    }

    operator bool(){
       return ptr;
    }

    type* get(){
        return ptr;
    }

    base_ptr<T>& operator=(base_ptr<T>&& other) noexcept {
       if (this == &other) return *this;
      
       reset();
       ptr = other.ptr;
       other.ptr = nullptr;
      
       return *this;
    }
};

template <typename T>
class unique_ptr : public base_ptr<T> {
public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T>&& other) 
    : base_ptr<T>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T>::ptr = ptr;
    }

    unique_ptr<T>& operator=(unique_ptr<T>&& other){
       base_ptr<T>::operator=( move(other) );

       return *this;
    }

    T* operator->() const {
       return base_ptr<T>::ptr;
    }

    T& operator*() const {
       return *base_ptr<T>::ptr;
    }

    ~unique_ptr(){
       base_ptr<T>::reset();
    }
};

template <typename T>
class unique_ptr<T[]> : public base_ptr<T[]> {
public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T[]>&& other) 
    : base_ptr<T[]>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T[]>::ptr = ptr;
    }

    unique_ptr<T[]>& operator=(unique_ptr<T[]>&& other){
       base_ptr<T[]>::operator=( move(other) );

       return *this;
    }

    T& operator[](int pos) const {
       return base_ptr<T[]>::ptr[pos];
    }

    ~unique_ptr(){
       base_ptr<T[]>::reset();
    }
};

template <class T, class ...Args>
enable_if_t<!is_array_v<T>, unique_ptr<T>>
make_unique(Args&& ...args)
{
   return unique_ptr<T>(new T(forward<Args>(args)...));
};

template <class T>
enable_if_t<is_array_v<T>, unique_ptr<T>>
make_unique(int size)
{
   using type = remove_extent_t<T>;
   return unique_ptr<T>(new type[size]);
};

int main() {
    unique_ptr<int> a (new int(1));
  
    unique_ptr<int> b;

    b.swap(a);

    b = make_unique<int>(2);

    b.reset();
  
    cout << "End" << endl;
  
    return 0;
}
#include <iostream>

using namespace std;

template<typename T>
class base_ptr {
private:
    using type = remove_extent_t<T>;

protected:
    type* ptr = nullptr;

public:
    base_ptr(){};
    
    base_ptr(base_ptr<T>&& other) noexcept
    : ptr(other.ptr) {
       other.ptr = nullptr;
    }

    type* release(){
       type* tmp = ptr;
       ptr = nullptr;
       return tmp;
    }

    void reset(){
       if(ptr != nullptr){
           if(is_array_v<T>)
               delete[] ptr;
            else
               delete ptr;
       }
       
       ptr = nullptr;
    }

    void reset(type* item) noexcept {
       reset();

       ptr = item;
    }

    void swap(base_ptr<T> &other) noexcept {
       type* tmp = ptr;

       ptr = other.ptr;
      
       other.ptr = tmp;
    }

    operator bool(){
       return ptr;
    }

    type* get(){
        return ptr;
    }

    base_ptr<T>& operator=(base_ptr<T>&& other) noexcept {
       if (this == &other) return *this;
      
       reset();
       ptr = other.ptr;
       other.ptr = nullptr;
      
       return *this;
    }
};

template <typename T>
class unique_ptr : public base_ptr<T> {
public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T>&& other) 
    : base_ptr<T>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T>::ptr = ptr;
    }

    unique_ptr<T>& operator=(unique_ptr<T>&& other){
       base_ptr<T>::operator=( move(other) );

       return *this;
    }

    T* operator->() const {
       return base_ptr<T>::ptr;
    }

    T& operator*() const {
       return *base_ptr<T>::ptr;
    }

    ~unique_ptr(){
       base_ptr<T>::reset();
    }
};

template <typename T>
class unique_ptr<T[]> : public base_ptr<T[]> {
public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T[]>&& other) 
    : base_ptr<T[]>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T[]>::ptr = ptr;
    }

    unique_ptr<T[]>& operator=(unique_ptr<T[]>&& other){
       base_ptr<T[]>::operator=( move(other) );

       return *this;
    }

    T& operator[](int pos) const {
       return base_ptr<T[]>::ptr[pos];
    }

    ~unique_ptr(){
       base_ptr<T[]>::reset();
    }
};

template <class T, class ...Args>
enable_if_t<!is_array_v<T>, unique_ptr<T>>
make_unique(Args&& ...args)
{
   return unique_ptr<T>(new T(forward<Args>(args)...));
};

template <class T>
enable_if_t<is_array_v<T>, unique_ptr<T>>
make_unique(int size)
{
   using type = remove_extent_t<T>;
   return unique_ptr<T>(new type[size]);
};

int main() {
    unique_ptr<int> a (new int(1));
  
    unique_ptr<int> b;

    b.swap(a);

    b = make_unique<int>(2);

    b.reset();
  
    cout << "End" << endl;
  
    return 0;
}
deleted 198 characters in body
Source Link
#include <iostream>

using namespace std;

template<typename T>
class base_ptr {
private:
    using type = remove_extent_t<T>;
    virtual void finish() = 0;

protected:
    type* ptr = nullptr;

public:
    base_ptr(){};

    base_ptr(const base_ptr<T>& other) = delete;

    base_ptr(base_ptr<T>&& other) noexcept
    : ptr(other.ptr) {
       other.ptr = nullptr;
    }

    type* release(){
       type* tmp = ptr;
       ptr = nullptr;
       return tmp;
    }

    void reset(){
       finishif(ptr != nullptr);{
           if(is_array_v<T>)
               delete[] ptr;
            else
               delete ptr;
       }
       
       ptr = nullptr;
    }

    void reset(type* item) noexcept {
       reset();

       ptr = item;
    }

    void swap(base_ptr<T> &other) noexcept {
       type* tmp = ptr;

       ptr = other.ptr;
      
       other.ptr = tmp;
    }

    operator bool(){
       return ptr;
    }

    type* get(){
        return ptr;
    }

    base_ptr<T>& operator=(base_ptr<T>&& other) noexcept {
       if (this == &other) return *this;
      
       reset();
       ptr = other.ptr;
       other.ptr = nullptr;
      
       return *this;
    }
};

template <typename T>
class unique_ptr : public base_ptr<T> {
private:
    void finish() noexcept {
       if(base_ptr<T>::ptr != nullptr)
          delete base_ptr<T>::ptr;
    }

public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T>&& other) 
    : base_ptr<T>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T>::ptr = ptr;
    }

    unique_ptr<T>& operator=(unique_ptr<T>&& other){
       base_ptr<T>::operator=( move(other) );

       return *this;
    }

    T* operator->() const {
       return base_ptr<T>::ptr;
    }

    T& operator*() const {
       return *base_ptr<T>::ptr;
    }

    ~unique_ptr(){
       finishbase_ptr<T>::reset();
    }
};

template <typename T>
class unique_ptr<T[]> : public base_ptr<T[]> {
private:
    void finish() noexcept {
       if(base_ptr<T[]>::ptr != nullptr)
          delete[] base_ptr<T[]>::ptr;
    }

public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T[]>&& other) 
    : base_ptr<T[]>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T[]>::ptr = ptr;
    }

    unique_ptr<T[]>& operator=(unique_ptr<T[]>&& other){
       base_ptr<T[]>::operator=( move(other) );

       return *this;
    }

    T& operator[](int pos) const {
       return base_ptr<T>base_ptr<T[]>::ptr[pos];
    }

    ~unique_ptr(){
       finishbase_ptr<T[]>::reset();
    }
};

template <class T, class ...Args>
enable_if_t<!is_array_v<T>, unique_ptr<T>>
make_unique(Args&& ...args)
{
   return unique_ptr<T>(new T(forward<Args>(args)...));
};

template <class T>
enable_if_t<is_array_v<T>, unique_ptr<T>>
make_unique(int size)
{
   using type = remove_extent_t<T>;
   return unique_ptr<T>(new type[size]);
};
 

int main() {
    unique_ptr<int> a (new int(1));
  
    unique_ptr<int> b;

    b.swap(a);

    b = make_unique<int>(2);

    b.reset();
  
    cout << "End" << endl;
  
    return 0;
}
#include <iostream>

using namespace std;

template<typename T>
class base_ptr {
private:
    using type = remove_extent_t<T>;
    virtual void finish() = 0;

protected:
    type* ptr = nullptr;

public:
    base_ptr(){};

    base_ptr(const base_ptr<T>& other) = delete;

    base_ptr(base_ptr<T>&& other) noexcept
    : ptr(other.ptr) {
       other.ptr = nullptr;
    }

    type* release(){
       type* tmp = ptr;
       ptr = nullptr;
       return tmp;
    }

    void reset(){
       finish();
       ptr = nullptr;
    }

    void reset(type* item) noexcept {
       reset();

       ptr = item;
    }

    void swap(base_ptr<T> &other) noexcept {
       type* tmp = ptr;

       ptr = other.ptr;
      
       other.ptr = tmp;
    }

    operator bool(){
       return ptr;
    }

    type* get(){
        return ptr;
    }

    base_ptr<T>& operator=(base_ptr<T>&& other) noexcept {
       if (this == &other) return *this;
      
       reset();
       ptr = other.ptr;
       other.ptr = nullptr;
      
       return *this;
    }
};

template <typename T>
class unique_ptr : public base_ptr<T> {
private:
    void finish() noexcept {
       if(base_ptr<T>::ptr != nullptr)
          delete base_ptr<T>::ptr;
    }

public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T>&& other) 
    : base_ptr<T>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T>::ptr = ptr;
    }

    unique_ptr<T>& operator=(unique_ptr<T>&& other){
       base_ptr<T>::operator=( move(other) );

       return *this;
    }

    T* operator->() const {
       return base_ptr<T>::ptr;
    }

    T& operator*() const {
       return *base_ptr<T>::ptr;
    }

    ~unique_ptr(){
       finish();
    }
};

template <typename T>
class unique_ptr<T[]> : public base_ptr<T[]> {
private:
    void finish() noexcept {
       if(base_ptr<T[]>::ptr != nullptr)
          delete[] base_ptr<T[]>::ptr;
    }

public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T[]>&& other) 
    : base_ptr<T[]>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T[]>::ptr = ptr;
    }

    unique_ptr<T[]>& operator=(unique_ptr<T[]>&& other){
       base_ptr<T[]>::operator=( move(other) );

       return *this;
    }

    T& operator[](int pos) const {
       return base_ptr<T>::ptr[pos];
    }

    ~unique_ptr(){
       finish();
    }
};

template <class T, class ...Args>
enable_if_t<!is_array_v<T>, unique_ptr<T>>
make_unique(Args&& ...args)
{
   return unique_ptr<T>(new T(forward<Args>(args)...));
};

template <class T>
enable_if_t<is_array_v<T>, unique_ptr<T>>
make_unique(int size)
{
   using type = remove_extent_t<T>;
   return unique_ptr<T>(new type[size]);
};
 

int main() {
    unique_ptr<int> a (new int(1));
  
    unique_ptr<int> b;

    b.swap(a);

    b = make_unique<int>(2);

    b.reset();
  
    cout << "End" << endl;
  
    return 0;
}
#include <iostream>

using namespace std;

template<typename T>
class base_ptr {
private:
    using type = remove_extent_t<T>;

protected:
    type* ptr = nullptr;

public:
    base_ptr(){};

    base_ptr(const base_ptr<T>& other) = delete;

    base_ptr(base_ptr<T>&& other) noexcept
    : ptr(other.ptr) {
       other.ptr = nullptr;
    }

    type* release(){
       type* tmp = ptr;
       ptr = nullptr;
       return tmp;
    }

    void reset(){
       if(ptr != nullptr){
           if(is_array_v<T>)
               delete[] ptr;
            else
               delete ptr;
       }
       
       ptr = nullptr;
    }

    void reset(type* item) noexcept {
       reset();

       ptr = item;
    }

    void swap(base_ptr<T> &other) noexcept {
       type* tmp = ptr;

       ptr = other.ptr;
      
       other.ptr = tmp;
    }

    operator bool(){
       return ptr;
    }

    type* get(){
        return ptr;
    }

    base_ptr<T>& operator=(base_ptr<T>&& other) noexcept {
       if (this == &other) return *this;
      
       reset();
       ptr = other.ptr;
       other.ptr = nullptr;
      
       return *this;
    }
};

template <typename T>
class unique_ptr : public base_ptr<T> {
public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T>&& other) 
    : base_ptr<T>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T>::ptr = ptr;
    }

    unique_ptr<T>& operator=(unique_ptr<T>&& other){
       base_ptr<T>::operator=( move(other) );

       return *this;
    }

    T* operator->() const {
       return base_ptr<T>::ptr;
    }

    T& operator*() const {
       return *base_ptr<T>::ptr;
    }

    ~unique_ptr(){
       base_ptr<T>::reset();
    }
};

template <typename T>
class unique_ptr<T[]> : public base_ptr<T[]> {
public:
    unique_ptr(){}

    unique_ptr(unique_ptr<T[]>&& other) 
    : base_ptr<T[]>(move(other)) { }

    explicit unique_ptr(T *ptr){
       base_ptr<T[]>::ptr = ptr;
    }

    unique_ptr<T[]>& operator=(unique_ptr<T[]>&& other){
       base_ptr<T[]>::operator=( move(other) );

       return *this;
    }

    T& operator[](int pos) const {
       return base_ptr<T[]>::ptr[pos];
    }

    ~unique_ptr(){
       base_ptr<T[]>::reset();
    }
};

template <class T, class ...Args>
enable_if_t<!is_array_v<T>, unique_ptr<T>>
make_unique(Args&& ...args)
{
   return unique_ptr<T>(new T(forward<Args>(args)...));
};

template <class T>
enable_if_t<is_array_v<T>, unique_ptr<T>>
make_unique(int size)
{
   using type = remove_extent_t<T>;
   return unique_ptr<T>(new type[size]);
};

int main() {
    unique_ptr<int> a (new int(1));
  
    unique_ptr<int> b;

    b.swap(a);

    b = make_unique<int>(2);

    b.reset();
  
    cout << "End" << endl;
  
    return 0;
}
Added recommendations.
Source Link
Loading
added 47 characters in body
Source Link
Loading
deleted 2 characters in body
Source Link
Loading
fixed grammar
Source Link
Loading
Source Link
Loading