Simple device (fancy) pointer implementationTrying to find a good design for reading in values of different types from a fileUnique pointer implementationHeap implementation using pointerSimple shared pointerArray-like container for uints shorter than 8 bits (Rev 1)Alternate “weak” pointer implementationPreferred implementation of `Array<T>::operator=(const Array<T> & rhs)`C++ maybe pointer type implementationAttempt at Smart Pointer ImplementationC++: Smart Pointer Implementation

Should I join office cleaning event for free?

How can I hide my bitcoin transactions to protect anonymity from others?

How to make payment on the internet without leaving a money trail?

How do we improve the relationship with a client software team that performs poorly and is becoming less collaborative?

How to type dʒ symbol (IPA) on Mac?

Why has Russell's definition of numbers using equivalence classes been finally abandoned? ( If it has actually been abandoned).

Compute hash value according to multiplication method

DOS, create pipe for stdin/stdout of command.com(or 4dos.com) in C or Batch?

Do Phineas and Ferb ever actually get busted in real time?

N.B. ligature in Latex

How old can references or sources in a thesis be?

Continuity at a point in terms of closure

Can a German sentence have two subjects?

The use of multiple foreign keys on same column in SQL Server

"which" command doesn't work / path of Safari?

whey we use polarized capacitor?

A newer friend of my brother's gave him a load of baseball cards that are supposedly extremely valuable. Is this a scam?

I’m planning on buying a laser printer but concerned about the life cycle of toner in the machine

How does one intimidate enemies without having the capacity for violence?

What would the Romans have called "sorcery"?

How do I create uniquely male characters?

How can bays and straits be determined in a procedurally generated map?

TGV timetables / schedules?

What exactly is the parasitic white layer that forms after iron parts are treated with ammonia?



Simple device (fancy) pointer implementation


Trying to find a good design for reading in values of different types from a fileUnique pointer implementationHeap implementation using pointerSimple shared pointerArray-like container for uints shorter than 8 bits (Rev 1)Alternate “weak” pointer implementationPreferred implementation of `Array<T>::operator=(const Array<T> & rhs)`C++ maybe pointer type implementationAttempt at Smart Pointer ImplementationC++: Smart Pointer Implementation






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








2












$begingroup$


device_raw_ptr is a simple fancy pointer. It essentially wrap pointers to GPU memory. It's sole purpose is to separate out host pointers from device pointers, i.e. they should not be inter-convertible and must not be dereferenced. At the same time, they should be zero-cost (with respect to raw host pointers) and be maximally compatible with regular pointers.



Helper class:



template <class T>
struct equality_operators
/*
** The deriving class must implement the following:
** friend bool operator==(const T&, const T&);
*/

friend bool operator!=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs == rhs);
;

template <class T>
struct less_than_operators
/*
** The deriving class must implement the following:
** friend bool operator<(const T&, const T&);
*/

friend bool operator>(const T& lhs, const T& rhs) return rhs < lhs;
friend bool operator<=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs > rhs);
friend bool operator>=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs < rhs);
;

template <class T>
struct relational_operators : equality_operators<T>, less_than_operators<T> ;


device_raw_ptr implementation:



template <class T>
class device_raw_ptr : public relational_operators<T>
static_assert(std::is_standard_layout<T>::value, "T must satisfy StandardLayoutType");
public:
using element_type = std::remove_extent_t<T>;

constexpr device_raw_ptr() noexcept = default;
constexpr device_raw_ptr(std::nullptr_t) noexcept : ptr nullptr
constexpr device_raw_ptr(const device_raw_ptr& other) noexcept = default;
explicit device_raw_ptr(element_type* ptr_) noexcept : ptr ptr_
device_raw_ptr(device_raw_ptr&& other) noexcept : ptr other.ptr other.reset();

device_raw_ptr& operator=(const device_raw_ptr& other) noexcept
swap(device_raw_ptr(other), *this);
return *this;


device_raw_ptr& operator=(device_raw_ptr&& other) noexcept
swap(device_raw_ptr(other), *this);
return *this;


void reset() noexcept ptr = nullptr;
void reset(T* ptr_) noexcept ptr = ptr_;

element_type* get() noexcept return ptr; ;
const element_type* get() const noexcept return ptr;

friend void swap(device_raw_ptr& lhs, device_raw_ptr& rhs) noexcept
using std::swap;
std::swap(lhs.ptr, rhs.ptr);


explicit operator bool() const noexcept return static_cast<bool>(ptr);

device_raw_ptr& operator++() noexcept
++ptr;
return *this;


device_raw_ptr operator++(int) noexcept
device_raw_ptr tmp(*this);
ptr++;
return tmp;


device_raw_ptr& operator+=(std::ptrdiff_t offset) noexcept
ptr += offset;
return *this;


device_raw_ptr& operator-=(std::ptrdiff_t offset) noexcept
ptr -= offset;
return *this;


friend device_raw_ptr& operator+(device_raw_ptr lhs, std::ptrdiff_t offset) noexcept
lhs += offset;
return lhs;


friend device_raw_ptr& operator-(device_raw_ptr lhs, std::ptrdiff_t offset) noexcept
lhs -= offset;
return lhs;


/* required by relational_operators base class */
friend bool operator==(const device_raw_ptr& lhs, const device_raw_ptr& rhs) noexcept return lhs.ptr == rhs.ptr;
friend bool operator<(const device_raw_ptr& lhs, const device_raw_ptr& rhs) noexcept return lhs.ptr < rhs.ptr;

protected:
T *ptr;
;

template <class T, class U, class V>
std::basic_ostream<U, V>& operator<<(std::basic_ostream<U, V>& os, const device_raw_ptr<T>& other)
os << other.get() << " (device)";
return os;



I am also looking for suggestions on how to order different things inside a class.



Might it be better to initialize with nullptr instead of the default constructor. This breaks compatibility but I think it might be worth considering the compiler would mostly optimize the assignment if it's immediately overwritten.










share|improve this question









New contributor




Yashas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$











  • $begingroup$
    I just noticed that I am passing rvalues to swap which accepts non-const lvalue as arguments. You can find it in the copy & move constructor.
    $endgroup$
    – Yashas
    6 hours ago

















2












$begingroup$


device_raw_ptr is a simple fancy pointer. It essentially wrap pointers to GPU memory. It's sole purpose is to separate out host pointers from device pointers, i.e. they should not be inter-convertible and must not be dereferenced. At the same time, they should be zero-cost (with respect to raw host pointers) and be maximally compatible with regular pointers.



Helper class:



template <class T>
struct equality_operators
/*
** The deriving class must implement the following:
** friend bool operator==(const T&, const T&);
*/

friend bool operator!=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs == rhs);
;

template <class T>
struct less_than_operators
/*
** The deriving class must implement the following:
** friend bool operator<(const T&, const T&);
*/

friend bool operator>(const T& lhs, const T& rhs) return rhs < lhs;
friend bool operator<=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs > rhs);
friend bool operator>=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs < rhs);
;

template <class T>
struct relational_operators : equality_operators<T>, less_than_operators<T> ;


device_raw_ptr implementation:



template <class T>
class device_raw_ptr : public relational_operators<T>
static_assert(std::is_standard_layout<T>::value, "T must satisfy StandardLayoutType");
public:
using element_type = std::remove_extent_t<T>;

constexpr device_raw_ptr() noexcept = default;
constexpr device_raw_ptr(std::nullptr_t) noexcept : ptr nullptr
constexpr device_raw_ptr(const device_raw_ptr& other) noexcept = default;
explicit device_raw_ptr(element_type* ptr_) noexcept : ptr ptr_
device_raw_ptr(device_raw_ptr&& other) noexcept : ptr other.ptr other.reset();

device_raw_ptr& operator=(const device_raw_ptr& other) noexcept
swap(device_raw_ptr(other), *this);
return *this;


device_raw_ptr& operator=(device_raw_ptr&& other) noexcept
swap(device_raw_ptr(other), *this);
return *this;


void reset() noexcept ptr = nullptr;
void reset(T* ptr_) noexcept ptr = ptr_;

element_type* get() noexcept return ptr; ;
const element_type* get() const noexcept return ptr;

friend void swap(device_raw_ptr& lhs, device_raw_ptr& rhs) noexcept
using std::swap;
std::swap(lhs.ptr, rhs.ptr);


explicit operator bool() const noexcept return static_cast<bool>(ptr);

device_raw_ptr& operator++() noexcept
++ptr;
return *this;


device_raw_ptr operator++(int) noexcept
device_raw_ptr tmp(*this);
ptr++;
return tmp;


device_raw_ptr& operator+=(std::ptrdiff_t offset) noexcept
ptr += offset;
return *this;


device_raw_ptr& operator-=(std::ptrdiff_t offset) noexcept
ptr -= offset;
return *this;


friend device_raw_ptr& operator+(device_raw_ptr lhs, std::ptrdiff_t offset) noexcept
lhs += offset;
return lhs;


friend device_raw_ptr& operator-(device_raw_ptr lhs, std::ptrdiff_t offset) noexcept
lhs -= offset;
return lhs;


/* required by relational_operators base class */
friend bool operator==(const device_raw_ptr& lhs, const device_raw_ptr& rhs) noexcept return lhs.ptr == rhs.ptr;
friend bool operator<(const device_raw_ptr& lhs, const device_raw_ptr& rhs) noexcept return lhs.ptr < rhs.ptr;

protected:
T *ptr;
;

template <class T, class U, class V>
std::basic_ostream<U, V>& operator<<(std::basic_ostream<U, V>& os, const device_raw_ptr<T>& other)
os << other.get() << " (device)";
return os;



I am also looking for suggestions on how to order different things inside a class.



Might it be better to initialize with nullptr instead of the default constructor. This breaks compatibility but I think it might be worth considering the compiler would mostly optimize the assignment if it's immediately overwritten.










share|improve this question









New contributor




Yashas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$











  • $begingroup$
    I just noticed that I am passing rvalues to swap which accepts non-const lvalue as arguments. You can find it in the copy & move constructor.
    $endgroup$
    – Yashas
    6 hours ago













2












2








2





$begingroup$


device_raw_ptr is a simple fancy pointer. It essentially wrap pointers to GPU memory. It's sole purpose is to separate out host pointers from device pointers, i.e. they should not be inter-convertible and must not be dereferenced. At the same time, they should be zero-cost (with respect to raw host pointers) and be maximally compatible with regular pointers.



Helper class:



template <class T>
struct equality_operators
/*
** The deriving class must implement the following:
** friend bool operator==(const T&, const T&);
*/

friend bool operator!=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs == rhs);
;

template <class T>
struct less_than_operators
/*
** The deriving class must implement the following:
** friend bool operator<(const T&, const T&);
*/

friend bool operator>(const T& lhs, const T& rhs) return rhs < lhs;
friend bool operator<=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs > rhs);
friend bool operator>=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs < rhs);
;

template <class T>
struct relational_operators : equality_operators<T>, less_than_operators<T> ;


device_raw_ptr implementation:



template <class T>
class device_raw_ptr : public relational_operators<T>
static_assert(std::is_standard_layout<T>::value, "T must satisfy StandardLayoutType");
public:
using element_type = std::remove_extent_t<T>;

constexpr device_raw_ptr() noexcept = default;
constexpr device_raw_ptr(std::nullptr_t) noexcept : ptr nullptr
constexpr device_raw_ptr(const device_raw_ptr& other) noexcept = default;
explicit device_raw_ptr(element_type* ptr_) noexcept : ptr ptr_
device_raw_ptr(device_raw_ptr&& other) noexcept : ptr other.ptr other.reset();

device_raw_ptr& operator=(const device_raw_ptr& other) noexcept
swap(device_raw_ptr(other), *this);
return *this;


device_raw_ptr& operator=(device_raw_ptr&& other) noexcept
swap(device_raw_ptr(other), *this);
return *this;


void reset() noexcept ptr = nullptr;
void reset(T* ptr_) noexcept ptr = ptr_;

element_type* get() noexcept return ptr; ;
const element_type* get() const noexcept return ptr;

friend void swap(device_raw_ptr& lhs, device_raw_ptr& rhs) noexcept
using std::swap;
std::swap(lhs.ptr, rhs.ptr);


explicit operator bool() const noexcept return static_cast<bool>(ptr);

device_raw_ptr& operator++() noexcept
++ptr;
return *this;


device_raw_ptr operator++(int) noexcept
device_raw_ptr tmp(*this);
ptr++;
return tmp;


device_raw_ptr& operator+=(std::ptrdiff_t offset) noexcept
ptr += offset;
return *this;


device_raw_ptr& operator-=(std::ptrdiff_t offset) noexcept
ptr -= offset;
return *this;


friend device_raw_ptr& operator+(device_raw_ptr lhs, std::ptrdiff_t offset) noexcept
lhs += offset;
return lhs;


friend device_raw_ptr& operator-(device_raw_ptr lhs, std::ptrdiff_t offset) noexcept
lhs -= offset;
return lhs;


/* required by relational_operators base class */
friend bool operator==(const device_raw_ptr& lhs, const device_raw_ptr& rhs) noexcept return lhs.ptr == rhs.ptr;
friend bool operator<(const device_raw_ptr& lhs, const device_raw_ptr& rhs) noexcept return lhs.ptr < rhs.ptr;

protected:
T *ptr;
;

template <class T, class U, class V>
std::basic_ostream<U, V>& operator<<(std::basic_ostream<U, V>& os, const device_raw_ptr<T>& other)
os << other.get() << " (device)";
return os;



I am also looking for suggestions on how to order different things inside a class.



Might it be better to initialize with nullptr instead of the default constructor. This breaks compatibility but I think it might be worth considering the compiler would mostly optimize the assignment if it's immediately overwritten.










share|improve this question









New contributor




Yashas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$




device_raw_ptr is a simple fancy pointer. It essentially wrap pointers to GPU memory. It's sole purpose is to separate out host pointers from device pointers, i.e. they should not be inter-convertible and must not be dereferenced. At the same time, they should be zero-cost (with respect to raw host pointers) and be maximally compatible with regular pointers.



Helper class:



template <class T>
struct equality_operators
/*
** The deriving class must implement the following:
** friend bool operator==(const T&, const T&);
*/

friend bool operator!=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs == rhs);
;

template <class T>
struct less_than_operators
/*
** The deriving class must implement the following:
** friend bool operator<(const T&, const T&);
*/

friend bool operator>(const T& lhs, const T& rhs) return rhs < lhs;
friend bool operator<=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs > rhs);
friend bool operator>=(const T& lhs, const T& rhs) return !static_cast<bool>(lhs < rhs);
;

template <class T>
struct relational_operators : equality_operators<T>, less_than_operators<T> ;


device_raw_ptr implementation:



template <class T>
class device_raw_ptr : public relational_operators<T>
static_assert(std::is_standard_layout<T>::value, "T must satisfy StandardLayoutType");
public:
using element_type = std::remove_extent_t<T>;

constexpr device_raw_ptr() noexcept = default;
constexpr device_raw_ptr(std::nullptr_t) noexcept : ptr nullptr
constexpr device_raw_ptr(const device_raw_ptr& other) noexcept = default;
explicit device_raw_ptr(element_type* ptr_) noexcept : ptr ptr_
device_raw_ptr(device_raw_ptr&& other) noexcept : ptr other.ptr other.reset();

device_raw_ptr& operator=(const device_raw_ptr& other) noexcept
swap(device_raw_ptr(other), *this);
return *this;


device_raw_ptr& operator=(device_raw_ptr&& other) noexcept
swap(device_raw_ptr(other), *this);
return *this;


void reset() noexcept ptr = nullptr;
void reset(T* ptr_) noexcept ptr = ptr_;

element_type* get() noexcept return ptr; ;
const element_type* get() const noexcept return ptr;

friend void swap(device_raw_ptr& lhs, device_raw_ptr& rhs) noexcept
using std::swap;
std::swap(lhs.ptr, rhs.ptr);


explicit operator bool() const noexcept return static_cast<bool>(ptr);

device_raw_ptr& operator++() noexcept
++ptr;
return *this;


device_raw_ptr operator++(int) noexcept
device_raw_ptr tmp(*this);
ptr++;
return tmp;


device_raw_ptr& operator+=(std::ptrdiff_t offset) noexcept
ptr += offset;
return *this;


device_raw_ptr& operator-=(std::ptrdiff_t offset) noexcept
ptr -= offset;
return *this;


friend device_raw_ptr& operator+(device_raw_ptr lhs, std::ptrdiff_t offset) noexcept
lhs += offset;
return lhs;


friend device_raw_ptr& operator-(device_raw_ptr lhs, std::ptrdiff_t offset) noexcept
lhs -= offset;
return lhs;


/* required by relational_operators base class */
friend bool operator==(const device_raw_ptr& lhs, const device_raw_ptr& rhs) noexcept return lhs.ptr == rhs.ptr;
friend bool operator<(const device_raw_ptr& lhs, const device_raw_ptr& rhs) noexcept return lhs.ptr < rhs.ptr;

protected:
T *ptr;
;

template <class T, class U, class V>
std::basic_ostream<U, V>& operator<<(std::basic_ostream<U, V>& os, const device_raw_ptr<T>& other)
os << other.get() << " (device)";
return os;



I am also looking for suggestions on how to order different things inside a class.



Might it be better to initialize with nullptr instead of the default constructor. This breaks compatibility but I think it might be worth considering the compiler would mostly optimize the assignment if it's immediately overwritten.







c++ c++11 pointers






share|improve this question









New contributor




Yashas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




Yashas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 5 hours ago









esote

3,01411039




3,01411039






New contributor




Yashas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 7 hours ago









YashasYashas

1113




1113




New contributor




Yashas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Yashas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Yashas is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











  • $begingroup$
    I just noticed that I am passing rvalues to swap which accepts non-const lvalue as arguments. You can find it in the copy & move constructor.
    $endgroup$
    – Yashas
    6 hours ago
















  • $begingroup$
    I just noticed that I am passing rvalues to swap which accepts non-const lvalue as arguments. You can find it in the copy & move constructor.
    $endgroup$
    – Yashas
    6 hours ago















$begingroup$
I just noticed that I am passing rvalues to swap which accepts non-const lvalue as arguments. You can find it in the copy & move constructor.
$endgroup$
– Yashas
6 hours ago




$begingroup$
I just noticed that I am passing rvalues to swap which accepts non-const lvalue as arguments. You can find it in the copy & move constructor.
$endgroup$
– Yashas
6 hours ago










2 Answers
2






active

oldest

votes


















1












$begingroup$

Helper classes



There is no need to use static_cast<bool> for your comparisons. The relational operators are already bool values. (If they are not, that is a problem with the definition of the operator for the type T.)



The standard <utility> header provides definitions for operator!= (from operator==) and operator>, operator<=, and operator>= (from operator<). There is no need for you to define those four operators if you have the other two (equality and less-than).



Why do you have the relational_operators struct at all? It shouldn't be necessary.



Implementation



The default constructor for device_raw_ptr leaves the ptr member uninitialized. Typically a class like this would initialize ptr to nullptr, and you wouldn't need the constructor that takes a std::nullptr_t object.



The copy assignment operator should just be ptr = other.ptr, since that is the only thing in your class. The way you have it is nonstandard behavior. You construct a temporary, then pass it as a non-const reference to swap. This is not supported as part of the language, although some compilers (MSVC) support it as an extension. You're constructing a temporary, doing a swap, then destroying the temporary (a noop in this case). Similarly, the move assignment operator can be simplified to not use the temporary (ptr = other.ptr; other.reset();, or use three statements with an assignment to a local to avoid problems if you move assign an object to itself).



operator bool does not need a static_cast. Perhaps an explicit ptr != nullptr check, although a pointer will implicitly convert to a bool.






share|improve this answer









$endgroup$












  • $begingroup$
    I thought using std::rel_ops is generally frowned upon. stackoverflow.com/questions/6225375/idiomatic-use-of-stdrel-ops suggests using boost:operators. I wrote my own version instead.
    $endgroup$
    – Yashas
    6 hours ago










  • $begingroup$
    The default constructor leaves ptr unitialized because that's how raw pointers behave (initialized with garbage?). But I am considering the option of initializing it to nullptr. The std::nullptr_t is a consequence of the aforementioned statement. I intended to have a constexpr constructor which sets ptr to nullptr.
    $endgroup$
    – Yashas
    6 hours ago










  • $begingroup$
    For the abuse of swap, I made started (codereview.stackexchange.com/questions/217019/…) using temporaries right after I posted the question. It was an attempt to reuse the constructors to perform move/copy but I think it was overkill for such a simple class.
    $endgroup$
    – Yashas
    6 hours ago











  • $begingroup$
    @Yashas std::rel_ops is there to avoid having duplicate definitions of those relational operators. If a class does not want some of them (as mentioned in your linked question), then it should define all of them, and = delete the ones it doesn't want to support. But its up to you to decide how to implement them.
    $endgroup$
    – 1201ProgramAlarm
    6 hours ago











  • $begingroup$
    @Yashas leaving raw pointer uninitialized is, generally, a bad idea. The cost of assigning a nullptr someplace where it isn't strictly necessary is outweighed by the predictability and consistent (mis)behavior the NULL value will give you.
    $endgroup$
    – 1201ProgramAlarm
    6 hours ago


















1












$begingroup$

  1. device_raw_ptr is extremely cheap to copy, so remove all hints of move-semantics and use of swap().


  2. Now you can remove the copy-constructor and copy-assignment, as there is no need to explicitly declare them. Especially making them user-defined must be avoided to keep them trivial.


  3. Kudos on trying to use the approved two-step for swap(). Though you get a failing grade anyway because you bungled it by using a qualified call in the second part. Hopefully, C++20 will abolish that nonsense by introducing customization point objects.


  4. Yes, you should pass your device_raw_ptr by value if you have the choice, as it is a tiny trivial type. Still, refrain from returning a reference to such a temporary.


  5. There is no reason operator-(device_raw_ptr, std::ptrdiff_t) should not be constexpr. Aside from your implementation for some reason delegating to operator-=, which is not. Same for operator+ which uses operator+=.


  6. Is there any reason you don't support subtracting a device_raw_ptr from another?


  7. I'm really puzzled why you make the only data-member protected instead of private.






share|improve this answer









$endgroup$













    Your Answer





    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );






    Yashas is a new contributor. Be nice, and check out our Code of Conduct.









    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217019%2fsimple-device-fancy-pointer-implementation%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1












    $begingroup$

    Helper classes



    There is no need to use static_cast<bool> for your comparisons. The relational operators are already bool values. (If they are not, that is a problem with the definition of the operator for the type T.)



    The standard <utility> header provides definitions for operator!= (from operator==) and operator>, operator<=, and operator>= (from operator<). There is no need for you to define those four operators if you have the other two (equality and less-than).



    Why do you have the relational_operators struct at all? It shouldn't be necessary.



    Implementation



    The default constructor for device_raw_ptr leaves the ptr member uninitialized. Typically a class like this would initialize ptr to nullptr, and you wouldn't need the constructor that takes a std::nullptr_t object.



    The copy assignment operator should just be ptr = other.ptr, since that is the only thing in your class. The way you have it is nonstandard behavior. You construct a temporary, then pass it as a non-const reference to swap. This is not supported as part of the language, although some compilers (MSVC) support it as an extension. You're constructing a temporary, doing a swap, then destroying the temporary (a noop in this case). Similarly, the move assignment operator can be simplified to not use the temporary (ptr = other.ptr; other.reset();, or use three statements with an assignment to a local to avoid problems if you move assign an object to itself).



    operator bool does not need a static_cast. Perhaps an explicit ptr != nullptr check, although a pointer will implicitly convert to a bool.






    share|improve this answer









    $endgroup$












    • $begingroup$
      I thought using std::rel_ops is generally frowned upon. stackoverflow.com/questions/6225375/idiomatic-use-of-stdrel-ops suggests using boost:operators. I wrote my own version instead.
      $endgroup$
      – Yashas
      6 hours ago










    • $begingroup$
      The default constructor leaves ptr unitialized because that's how raw pointers behave (initialized with garbage?). But I am considering the option of initializing it to nullptr. The std::nullptr_t is a consequence of the aforementioned statement. I intended to have a constexpr constructor which sets ptr to nullptr.
      $endgroup$
      – Yashas
      6 hours ago










    • $begingroup$
      For the abuse of swap, I made started (codereview.stackexchange.com/questions/217019/…) using temporaries right after I posted the question. It was an attempt to reuse the constructors to perform move/copy but I think it was overkill for such a simple class.
      $endgroup$
      – Yashas
      6 hours ago











    • $begingroup$
      @Yashas std::rel_ops is there to avoid having duplicate definitions of those relational operators. If a class does not want some of them (as mentioned in your linked question), then it should define all of them, and = delete the ones it doesn't want to support. But its up to you to decide how to implement them.
      $endgroup$
      – 1201ProgramAlarm
      6 hours ago











    • $begingroup$
      @Yashas leaving raw pointer uninitialized is, generally, a bad idea. The cost of assigning a nullptr someplace where it isn't strictly necessary is outweighed by the predictability and consistent (mis)behavior the NULL value will give you.
      $endgroup$
      – 1201ProgramAlarm
      6 hours ago















    1












    $begingroup$

    Helper classes



    There is no need to use static_cast<bool> for your comparisons. The relational operators are already bool values. (If they are not, that is a problem with the definition of the operator for the type T.)



    The standard <utility> header provides definitions for operator!= (from operator==) and operator>, operator<=, and operator>= (from operator<). There is no need for you to define those four operators if you have the other two (equality and less-than).



    Why do you have the relational_operators struct at all? It shouldn't be necessary.



    Implementation



    The default constructor for device_raw_ptr leaves the ptr member uninitialized. Typically a class like this would initialize ptr to nullptr, and you wouldn't need the constructor that takes a std::nullptr_t object.



    The copy assignment operator should just be ptr = other.ptr, since that is the only thing in your class. The way you have it is nonstandard behavior. You construct a temporary, then pass it as a non-const reference to swap. This is not supported as part of the language, although some compilers (MSVC) support it as an extension. You're constructing a temporary, doing a swap, then destroying the temporary (a noop in this case). Similarly, the move assignment operator can be simplified to not use the temporary (ptr = other.ptr; other.reset();, or use three statements with an assignment to a local to avoid problems if you move assign an object to itself).



    operator bool does not need a static_cast. Perhaps an explicit ptr != nullptr check, although a pointer will implicitly convert to a bool.






    share|improve this answer









    $endgroup$












    • $begingroup$
      I thought using std::rel_ops is generally frowned upon. stackoverflow.com/questions/6225375/idiomatic-use-of-stdrel-ops suggests using boost:operators. I wrote my own version instead.
      $endgroup$
      – Yashas
      6 hours ago










    • $begingroup$
      The default constructor leaves ptr unitialized because that's how raw pointers behave (initialized with garbage?). But I am considering the option of initializing it to nullptr. The std::nullptr_t is a consequence of the aforementioned statement. I intended to have a constexpr constructor which sets ptr to nullptr.
      $endgroup$
      – Yashas
      6 hours ago










    • $begingroup$
      For the abuse of swap, I made started (codereview.stackexchange.com/questions/217019/…) using temporaries right after I posted the question. It was an attempt to reuse the constructors to perform move/copy but I think it was overkill for such a simple class.
      $endgroup$
      – Yashas
      6 hours ago











    • $begingroup$
      @Yashas std::rel_ops is there to avoid having duplicate definitions of those relational operators. If a class does not want some of them (as mentioned in your linked question), then it should define all of them, and = delete the ones it doesn't want to support. But its up to you to decide how to implement them.
      $endgroup$
      – 1201ProgramAlarm
      6 hours ago











    • $begingroup$
      @Yashas leaving raw pointer uninitialized is, generally, a bad idea. The cost of assigning a nullptr someplace where it isn't strictly necessary is outweighed by the predictability and consistent (mis)behavior the NULL value will give you.
      $endgroup$
      – 1201ProgramAlarm
      6 hours ago













    1












    1








    1





    $begingroup$

    Helper classes



    There is no need to use static_cast<bool> for your comparisons. The relational operators are already bool values. (If they are not, that is a problem with the definition of the operator for the type T.)



    The standard <utility> header provides definitions for operator!= (from operator==) and operator>, operator<=, and operator>= (from operator<). There is no need for you to define those four operators if you have the other two (equality and less-than).



    Why do you have the relational_operators struct at all? It shouldn't be necessary.



    Implementation



    The default constructor for device_raw_ptr leaves the ptr member uninitialized. Typically a class like this would initialize ptr to nullptr, and you wouldn't need the constructor that takes a std::nullptr_t object.



    The copy assignment operator should just be ptr = other.ptr, since that is the only thing in your class. The way you have it is nonstandard behavior. You construct a temporary, then pass it as a non-const reference to swap. This is not supported as part of the language, although some compilers (MSVC) support it as an extension. You're constructing a temporary, doing a swap, then destroying the temporary (a noop in this case). Similarly, the move assignment operator can be simplified to not use the temporary (ptr = other.ptr; other.reset();, or use three statements with an assignment to a local to avoid problems if you move assign an object to itself).



    operator bool does not need a static_cast. Perhaps an explicit ptr != nullptr check, although a pointer will implicitly convert to a bool.






    share|improve this answer









    $endgroup$



    Helper classes



    There is no need to use static_cast<bool> for your comparisons. The relational operators are already bool values. (If they are not, that is a problem with the definition of the operator for the type T.)



    The standard <utility> header provides definitions for operator!= (from operator==) and operator>, operator<=, and operator>= (from operator<). There is no need for you to define those four operators if you have the other two (equality and less-than).



    Why do you have the relational_operators struct at all? It shouldn't be necessary.



    Implementation



    The default constructor for device_raw_ptr leaves the ptr member uninitialized. Typically a class like this would initialize ptr to nullptr, and you wouldn't need the constructor that takes a std::nullptr_t object.



    The copy assignment operator should just be ptr = other.ptr, since that is the only thing in your class. The way you have it is nonstandard behavior. You construct a temporary, then pass it as a non-const reference to swap. This is not supported as part of the language, although some compilers (MSVC) support it as an extension. You're constructing a temporary, doing a swap, then destroying the temporary (a noop in this case). Similarly, the move assignment operator can be simplified to not use the temporary (ptr = other.ptr; other.reset();, or use three statements with an assignment to a local to avoid problems if you move assign an object to itself).



    operator bool does not need a static_cast. Perhaps an explicit ptr != nullptr check, although a pointer will implicitly convert to a bool.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered 6 hours ago









    1201ProgramAlarm1201ProgramAlarm

    3,7032925




    3,7032925











    • $begingroup$
      I thought using std::rel_ops is generally frowned upon. stackoverflow.com/questions/6225375/idiomatic-use-of-stdrel-ops suggests using boost:operators. I wrote my own version instead.
      $endgroup$
      – Yashas
      6 hours ago










    • $begingroup$
      The default constructor leaves ptr unitialized because that's how raw pointers behave (initialized with garbage?). But I am considering the option of initializing it to nullptr. The std::nullptr_t is a consequence of the aforementioned statement. I intended to have a constexpr constructor which sets ptr to nullptr.
      $endgroup$
      – Yashas
      6 hours ago










    • $begingroup$
      For the abuse of swap, I made started (codereview.stackexchange.com/questions/217019/…) using temporaries right after I posted the question. It was an attempt to reuse the constructors to perform move/copy but I think it was overkill for such a simple class.
      $endgroup$
      – Yashas
      6 hours ago











    • $begingroup$
      @Yashas std::rel_ops is there to avoid having duplicate definitions of those relational operators. If a class does not want some of them (as mentioned in your linked question), then it should define all of them, and = delete the ones it doesn't want to support. But its up to you to decide how to implement them.
      $endgroup$
      – 1201ProgramAlarm
      6 hours ago











    • $begingroup$
      @Yashas leaving raw pointer uninitialized is, generally, a bad idea. The cost of assigning a nullptr someplace where it isn't strictly necessary is outweighed by the predictability and consistent (mis)behavior the NULL value will give you.
      $endgroup$
      – 1201ProgramAlarm
      6 hours ago
















    • $begingroup$
      I thought using std::rel_ops is generally frowned upon. stackoverflow.com/questions/6225375/idiomatic-use-of-stdrel-ops suggests using boost:operators. I wrote my own version instead.
      $endgroup$
      – Yashas
      6 hours ago










    • $begingroup$
      The default constructor leaves ptr unitialized because that's how raw pointers behave (initialized with garbage?). But I am considering the option of initializing it to nullptr. The std::nullptr_t is a consequence of the aforementioned statement. I intended to have a constexpr constructor which sets ptr to nullptr.
      $endgroup$
      – Yashas
      6 hours ago










    • $begingroup$
      For the abuse of swap, I made started (codereview.stackexchange.com/questions/217019/…) using temporaries right after I posted the question. It was an attempt to reuse the constructors to perform move/copy but I think it was overkill for such a simple class.
      $endgroup$
      – Yashas
      6 hours ago











    • $begingroup$
      @Yashas std::rel_ops is there to avoid having duplicate definitions of those relational operators. If a class does not want some of them (as mentioned in your linked question), then it should define all of them, and = delete the ones it doesn't want to support. But its up to you to decide how to implement them.
      $endgroup$
      – 1201ProgramAlarm
      6 hours ago











    • $begingroup$
      @Yashas leaving raw pointer uninitialized is, generally, a bad idea. The cost of assigning a nullptr someplace where it isn't strictly necessary is outweighed by the predictability and consistent (mis)behavior the NULL value will give you.
      $endgroup$
      – 1201ProgramAlarm
      6 hours ago















    $begingroup$
    I thought using std::rel_ops is generally frowned upon. stackoverflow.com/questions/6225375/idiomatic-use-of-stdrel-ops suggests using boost:operators. I wrote my own version instead.
    $endgroup$
    – Yashas
    6 hours ago




    $begingroup$
    I thought using std::rel_ops is generally frowned upon. stackoverflow.com/questions/6225375/idiomatic-use-of-stdrel-ops suggests using boost:operators. I wrote my own version instead.
    $endgroup$
    – Yashas
    6 hours ago












    $begingroup$
    The default constructor leaves ptr unitialized because that's how raw pointers behave (initialized with garbage?). But I am considering the option of initializing it to nullptr. The std::nullptr_t is a consequence of the aforementioned statement. I intended to have a constexpr constructor which sets ptr to nullptr.
    $endgroup$
    – Yashas
    6 hours ago




    $begingroup$
    The default constructor leaves ptr unitialized because that's how raw pointers behave (initialized with garbage?). But I am considering the option of initializing it to nullptr. The std::nullptr_t is a consequence of the aforementioned statement. I intended to have a constexpr constructor which sets ptr to nullptr.
    $endgroup$
    – Yashas
    6 hours ago












    $begingroup$
    For the abuse of swap, I made started (codereview.stackexchange.com/questions/217019/…) using temporaries right after I posted the question. It was an attempt to reuse the constructors to perform move/copy but I think it was overkill for such a simple class.
    $endgroup$
    – Yashas
    6 hours ago





    $begingroup$
    For the abuse of swap, I made started (codereview.stackexchange.com/questions/217019/…) using temporaries right after I posted the question. It was an attempt to reuse the constructors to perform move/copy but I think it was overkill for such a simple class.
    $endgroup$
    – Yashas
    6 hours ago













    $begingroup$
    @Yashas std::rel_ops is there to avoid having duplicate definitions of those relational operators. If a class does not want some of them (as mentioned in your linked question), then it should define all of them, and = delete the ones it doesn't want to support. But its up to you to decide how to implement them.
    $endgroup$
    – 1201ProgramAlarm
    6 hours ago





    $begingroup$
    @Yashas std::rel_ops is there to avoid having duplicate definitions of those relational operators. If a class does not want some of them (as mentioned in your linked question), then it should define all of them, and = delete the ones it doesn't want to support. But its up to you to decide how to implement them.
    $endgroup$
    – 1201ProgramAlarm
    6 hours ago













    $begingroup$
    @Yashas leaving raw pointer uninitialized is, generally, a bad idea. The cost of assigning a nullptr someplace where it isn't strictly necessary is outweighed by the predictability and consistent (mis)behavior the NULL value will give you.
    $endgroup$
    – 1201ProgramAlarm
    6 hours ago




    $begingroup$
    @Yashas leaving raw pointer uninitialized is, generally, a bad idea. The cost of assigning a nullptr someplace where it isn't strictly necessary is outweighed by the predictability and consistent (mis)behavior the NULL value will give you.
    $endgroup$
    – 1201ProgramAlarm
    6 hours ago













    1












    $begingroup$

    1. device_raw_ptr is extremely cheap to copy, so remove all hints of move-semantics and use of swap().


    2. Now you can remove the copy-constructor and copy-assignment, as there is no need to explicitly declare them. Especially making them user-defined must be avoided to keep them trivial.


    3. Kudos on trying to use the approved two-step for swap(). Though you get a failing grade anyway because you bungled it by using a qualified call in the second part. Hopefully, C++20 will abolish that nonsense by introducing customization point objects.


    4. Yes, you should pass your device_raw_ptr by value if you have the choice, as it is a tiny trivial type. Still, refrain from returning a reference to such a temporary.


    5. There is no reason operator-(device_raw_ptr, std::ptrdiff_t) should not be constexpr. Aside from your implementation for some reason delegating to operator-=, which is not. Same for operator+ which uses operator+=.


    6. Is there any reason you don't support subtracting a device_raw_ptr from another?


    7. I'm really puzzled why you make the only data-member protected instead of private.






    share|improve this answer









    $endgroup$

















      1












      $begingroup$

      1. device_raw_ptr is extremely cheap to copy, so remove all hints of move-semantics and use of swap().


      2. Now you can remove the copy-constructor and copy-assignment, as there is no need to explicitly declare them. Especially making them user-defined must be avoided to keep them trivial.


      3. Kudos on trying to use the approved two-step for swap(). Though you get a failing grade anyway because you bungled it by using a qualified call in the second part. Hopefully, C++20 will abolish that nonsense by introducing customization point objects.


      4. Yes, you should pass your device_raw_ptr by value if you have the choice, as it is a tiny trivial type. Still, refrain from returning a reference to such a temporary.


      5. There is no reason operator-(device_raw_ptr, std::ptrdiff_t) should not be constexpr. Aside from your implementation for some reason delegating to operator-=, which is not. Same for operator+ which uses operator+=.


      6. Is there any reason you don't support subtracting a device_raw_ptr from another?


      7. I'm really puzzled why you make the only data-member protected instead of private.






      share|improve this answer









      $endgroup$















        1












        1








        1





        $begingroup$

        1. device_raw_ptr is extremely cheap to copy, so remove all hints of move-semantics and use of swap().


        2. Now you can remove the copy-constructor and copy-assignment, as there is no need to explicitly declare them. Especially making them user-defined must be avoided to keep them trivial.


        3. Kudos on trying to use the approved two-step for swap(). Though you get a failing grade anyway because you bungled it by using a qualified call in the second part. Hopefully, C++20 will abolish that nonsense by introducing customization point objects.


        4. Yes, you should pass your device_raw_ptr by value if you have the choice, as it is a tiny trivial type. Still, refrain from returning a reference to such a temporary.


        5. There is no reason operator-(device_raw_ptr, std::ptrdiff_t) should not be constexpr. Aside from your implementation for some reason delegating to operator-=, which is not. Same for operator+ which uses operator+=.


        6. Is there any reason you don't support subtracting a device_raw_ptr from another?


        7. I'm really puzzled why you make the only data-member protected instead of private.






        share|improve this answer









        $endgroup$



        1. device_raw_ptr is extremely cheap to copy, so remove all hints of move-semantics and use of swap().


        2. Now you can remove the copy-constructor and copy-assignment, as there is no need to explicitly declare them. Especially making them user-defined must be avoided to keep them trivial.


        3. Kudos on trying to use the approved two-step for swap(). Though you get a failing grade anyway because you bungled it by using a qualified call in the second part. Hopefully, C++20 will abolish that nonsense by introducing customization point objects.


        4. Yes, you should pass your device_raw_ptr by value if you have the choice, as it is a tiny trivial type. Still, refrain from returning a reference to such a temporary.


        5. There is no reason operator-(device_raw_ptr, std::ptrdiff_t) should not be constexpr. Aside from your implementation for some reason delegating to operator-=, which is not. Same for operator+ which uses operator+=.


        6. Is there any reason you don't support subtracting a device_raw_ptr from another?


        7. I'm really puzzled why you make the only data-member protected instead of private.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 3 hours ago









        DeduplicatorDeduplicator

        11.8k1950




        11.8k1950




















            Yashas is a new contributor. Be nice, and check out our Code of Conduct.









            draft saved

            draft discarded


















            Yashas is a new contributor. Be nice, and check out our Code of Conduct.












            Yashas is a new contributor. Be nice, and check out our Code of Conduct.











            Yashas is a new contributor. Be nice, and check out our Code of Conduct.














            Thanks for contributing an answer to Code Review Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            Use MathJax to format equations. MathJax reference.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f217019%2fsimple-device-fancy-pointer-implementation%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Oświęcim Innehåll Historia | Källor | Externa länkar | Navigeringsmeny50°2′18″N 19°13′17″Ö / 50.03833°N 19.22139°Ö / 50.03833; 19.2213950°2′18″N 19°13′17″Ö / 50.03833°N 19.22139°Ö / 50.03833; 19.221393089658Nordisk familjebok, AuschwitzInsidan tro och existensJewish Community i OświęcimAuschwitz Jewish Center: MuseumAuschwitz Jewish Center

            Valle di Casies Indice Geografia fisica | Origini del nome | Storia | Società | Amministrazione | Sport | Note | Bibliografia | Voci correlate | Altri progetti | Collegamenti esterni | Menu di navigazione46°46′N 12°11′E / 46.766667°N 12.183333°E46.766667; 12.183333 (Valle di Casies)46°46′N 12°11′E / 46.766667°N 12.183333°E46.766667; 12.183333 (Valle di Casies)Sito istituzionaleAstat Censimento della popolazione 2011 - Determinazione della consistenza dei tre gruppi linguistici della Provincia Autonoma di Bolzano-Alto Adige - giugno 2012Numeri e fattiValle di CasiesDato IstatTabella dei gradi/giorno dei Comuni italiani raggruppati per Regione e Provincia26 agosto 1993, n. 412Heraldry of the World: GsiesStatistiche I.StatValCasies.comWikimedia CommonsWikimedia CommonsValle di CasiesSito ufficialeValle di CasiesMM14870458910042978-6

            Typsetting diagram chases (with TikZ?) Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)How to define the default vertical distance between nodes?Draw edge on arcNumerical conditional within tikz keys?TikZ: Drawing an arc from an intersection to an intersectionDrawing rectilinear curves in Tikz, aka an Etch-a-Sketch drawingLine up nested tikz enviroments or how to get rid of themHow to place nodes in an absolute coordinate system in tikzCommutative diagram with curve connecting between nodesTikz with standalone: pinning tikz coordinates to page cmDrawing a Decision Diagram with Tikz and layout manager