HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Yet another shared pointer

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
yetpointeranothershared

Problem

What might be wrong with this shared pointer? One good point of it might be, that it should handle array types correctly by default (e.g. light_ptr(new int[10]).

std::shared_ptr has the advantage of being more portable. For example, emscripten provides an implementation, but light_ptr won't compile, still, it can be ported to emscripten easily. The native implementation may also be more optimized.

```
#pragma once
#ifndef LIGHTPTR_HPP
# define LIGHTPTR_HPP

#include

#include

#include

#include

#include

namespace detail
{
using counter_type = ::std::size_t;

using atomic_type = ::std::atomic;

template
using deleter_type = void ()(T);

template
struct ref_type
{
using type = U&;
};

template <>
struct ref_type
{
using type = void;
};

template
inline void dec_ref(atomic_type* const counter_ptr,
T* const ptr, deleter_type const deleter)
{
if (counter_ptr && (counter_type(1) ==
counter_ptr->fetch_sub(counter_type(1), ::std::memory_order_relaxed)))
{
delete counter_ptr;

deleter(ptr);
}
// else do nothing
}

inline void inc_ref(atomic_type* const counter_ptr)
{
assert(counter_ptr);
counter_ptr->fetch_add(counter_type(1), ::std::memory_order_relaxed);
}
}

template
struct light_ptr
{
template
struct deletion_type
{
using type = V;
};

template
struct deletion_type
{
using type = V[];
};

template
struct deletion_type
{
using type = V[];
};

template
struct remove_array
{
using type = U;
};

template
struct remove_array
{
using type = U;
};

template
struct remove_array
{
using type = U;
};

using element_type = typename remove_array::type;

using deleter_type = ::detail::deleter_type;

light_ptr() = default;

template
explicit light_ptr(U* const p,
deleter_type const d = default_deleter)
{
reset(p, d);
}

~light_ptr() { ::detail::dec_ref(counter_ptr_, p

Solution

The move assignment operator is broken:

light_ptr& operator=(light_ptr&& rhs) noexcept


You over write the current members with the values from the rhs, but do not decrement the reference counter before overwriting. It might be easier to swap *this with rhs.

Don't include types that are not being used:

template 
  struct deletion_type
  {
    using type = V[];
  };

  template 
  struct remove_array
  {
    using type = U;
  };


Casting to void*. Once this is done the only valid operation is to cast back to the original type. Annything else is undefined.

return static_cast(static_cast(ptr_));


In this case element_type is the same as T. But the code is written in such a way that any changes by a maintainer can easily result in this being not true. Also I don;t actually see the need for a cast.

Code Snippets

light_ptr& operator=(light_ptr&& rhs) noexcept
template <typename U, typename V, ::std::size_t N>
  struct deletion_type<U[N], V>
  {
    using type = V[];
  };

  template <typename U, ::std::size_t N>
  struct remove_array<U[N]>
  {
    using type = U;
  };
return static_cast<T*>(static_cast<void*>(ptr_));

Context

StackExchange Code Review Q#30398, answer score: 4

Revisions (0)

No revisions yet.