0fa7617d84
I recently learned that move constructors generally should be marked "noexcept". This ensures that standard containers will move objects when possible, rather than copy them. This patch fixes the cases I could find. Note that implicitly-defined or defaulted move constructors will automatically do what you'd expect; that is, they are noexcept if all the members have noexcept move constructors. While doing this, I noticed a couple of odd cases where the move constructor seemed to assume that the object being constructed could have state requiring destruction. I've fixed these as well. See completion_result and scoped_mmap. gdb/ChangeLog 2020-04-20 Tom Tromey <tromey@adacore.com> * python/python.c (struct gdbpy_event): Mark move constructor as noexcept. * python/py-tui.c (class gdbpy_tui_window_maker): Mark move constructor as noexcept. * completer.h (struct completion_result): Mark move constructor as noexcept. * completer.c (completion_result::completion_result): Use initialization style. Don't call reset_match_list. gdbsupport/ChangeLog 2020-04-20 Tom Tromey <tromey@adacore.com> * scoped_mmap.h (scoped_mmap): Mark move constructor as noexcept. Use initialization style. Don't call destroy. * scoped_fd.h (class scoped_fd): Mark move constructor as noexcept. * gdb_ref_ptr.h (class ref_ptr): Mark move constructor as noexcept.
229 lines
5.4 KiB
C++
229 lines
5.4 KiB
C++
/* Reference-counted smart pointer class
|
|
|
|
Copyright (C) 2016-2020 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef COMMON_GDB_REF_PTR_H
|
|
#define COMMON_GDB_REF_PTR_H
|
|
|
|
#include <cstddef>
|
|
|
|
namespace gdb
|
|
{
|
|
|
|
/* An instance of this class either holds a reference to a
|
|
reference-counted object or is "NULL". Reference counting is
|
|
handled externally by a policy class. If the object holds a
|
|
reference, then when the object is destroyed, the reference is
|
|
decref'd.
|
|
|
|
Normally an instance is constructed using a pointer. This sort of
|
|
initialization lets this class manage the lifetime of that
|
|
reference.
|
|
|
|
Assignment and copy construction will make a new reference as
|
|
appropriate. Assignment from a plain pointer is disallowed to
|
|
avoid confusion about whether this acquires a new reference;
|
|
instead use the "reset" method -- which, like the pointer
|
|
constructor, transfers ownership.
|
|
|
|
The policy class must provide two static methods:
|
|
void incref (T *);
|
|
void decref (T *);
|
|
*/
|
|
template<typename T, typename Policy>
|
|
class ref_ptr
|
|
{
|
|
public:
|
|
|
|
/* Create a new NULL instance. */
|
|
ref_ptr ()
|
|
: m_obj (NULL)
|
|
{
|
|
}
|
|
|
|
/* Create a new NULL instance. Note that this is not explicit. */
|
|
ref_ptr (const std::nullptr_t)
|
|
: m_obj (NULL)
|
|
{
|
|
}
|
|
|
|
/* Create a new instance. OBJ is a reference, management of which
|
|
is now transferred to this class. */
|
|
explicit ref_ptr (T *obj)
|
|
: m_obj (obj)
|
|
{
|
|
}
|
|
|
|
/* Copy another instance. */
|
|
ref_ptr (const ref_ptr &other)
|
|
: m_obj (other.m_obj)
|
|
{
|
|
if (m_obj != NULL)
|
|
Policy::incref (m_obj);
|
|
}
|
|
|
|
/* Transfer ownership from OTHER. */
|
|
ref_ptr (ref_ptr &&other) noexcept
|
|
: m_obj (other.m_obj)
|
|
{
|
|
other.m_obj = NULL;
|
|
}
|
|
|
|
/* Destroy this instance. */
|
|
~ref_ptr ()
|
|
{
|
|
if (m_obj != NULL)
|
|
Policy::decref (m_obj);
|
|
}
|
|
|
|
/* Copy another instance. */
|
|
ref_ptr &operator= (const ref_ptr &other)
|
|
{
|
|
/* Do nothing on self-assignment. */
|
|
if (this != &other)
|
|
{
|
|
reset (other.m_obj);
|
|
if (m_obj != NULL)
|
|
Policy::incref (m_obj);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/* Transfer ownership from OTHER. */
|
|
ref_ptr &operator= (ref_ptr &&other)
|
|
{
|
|
/* Do nothing on self-assignment. */
|
|
if (this != &other)
|
|
{
|
|
reset (other.m_obj);
|
|
other.m_obj = NULL;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/* Change this instance's referent. OBJ is a reference, management
|
|
of which is now transferred to this class. */
|
|
void reset (T *obj)
|
|
{
|
|
if (m_obj != NULL)
|
|
Policy::decref (m_obj);
|
|
m_obj = obj;
|
|
}
|
|
|
|
/* Return this instance's referent without changing the state of
|
|
this class. */
|
|
T *get () const
|
|
{
|
|
return m_obj;
|
|
}
|
|
|
|
/* Return this instance's referent, and stop managing this
|
|
reference. The caller is now responsible for the ownership of
|
|
the reference. */
|
|
ATTRIBUTE_UNUSED_RESULT T *release ()
|
|
{
|
|
T *result = m_obj;
|
|
|
|
m_obj = NULL;
|
|
return result;
|
|
}
|
|
|
|
/* Let users refer to members of the underlying pointer. */
|
|
T *operator-> () const
|
|
{
|
|
return m_obj;
|
|
}
|
|
|
|
/* Acquire a new reference and return a ref_ptr that owns it. */
|
|
static ref_ptr<T, Policy> new_reference (T *obj)
|
|
{
|
|
Policy::incref (obj);
|
|
return ref_ptr<T, Policy> (obj);
|
|
}
|
|
|
|
private:
|
|
|
|
T *m_obj;
|
|
};
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator== (const ref_ptr<T, Policy> &lhs,
|
|
const ref_ptr<T, Policy> &rhs)
|
|
{
|
|
return lhs.get () == rhs.get ();
|
|
}
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator== (const ref_ptr<T, Policy> &lhs, const T *rhs)
|
|
{
|
|
return lhs.get () == rhs;
|
|
}
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator== (const ref_ptr<T, Policy> &lhs, const std::nullptr_t)
|
|
{
|
|
return lhs.get () == nullptr;
|
|
}
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator== (const T *lhs, const ref_ptr<T, Policy> &rhs)
|
|
{
|
|
return lhs == rhs.get ();
|
|
}
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator== (const std::nullptr_t, const ref_ptr<T, Policy> &rhs)
|
|
{
|
|
return nullptr == rhs.get ();
|
|
}
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator!= (const ref_ptr<T, Policy> &lhs,
|
|
const ref_ptr<T, Policy> &rhs)
|
|
{
|
|
return lhs.get () != rhs.get ();
|
|
}
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator!= (const ref_ptr<T, Policy> &lhs, const T *rhs)
|
|
{
|
|
return lhs.get () != rhs;
|
|
}
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator!= (const ref_ptr<T, Policy> &lhs, const std::nullptr_t)
|
|
{
|
|
return lhs.get () != nullptr;
|
|
}
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator!= (const T *lhs, const ref_ptr<T, Policy> &rhs)
|
|
{
|
|
return lhs != rhs.get ();
|
|
}
|
|
|
|
template<typename T, typename Policy>
|
|
inline bool operator!= (const std::nullptr_t, const ref_ptr<T, Policy> &rhs)
|
|
{
|
|
return nullptr != rhs.get ();
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* COMMON_GDB_REF_PTR_H */
|