Make std::function tolerate semantically non-CopyConstructible objects
To satisfy the CopyConstructible requirement a callable object stored in a std::function must behave the same when copied from a const or non-const source. If copying a non-const object doesn't produce an equivalent copy then the behaviour is undefined. But we can make our std::function more tolerant of such objects by ensuring we always copy from a const lvalue. Additionally use an if constexpr statement in the _M_get_pointer function to avoid unnecessary instantiations in the discarded branch. * include/bits/std_function.h (_Base_manager::_M_get_pointer): Use constexpr if in C++17 mode. (_Base_manager::_M_clone(_Any_data&, const _Any_data&, true_type)): Copy from const object. * testsuite/20_util/function/cons/non_copyconstructible.cc: New. From-SVN: r260080
This commit is contained in:
parent
a296d6d3bd
commit
88b1e41c2d
3 changed files with 57 additions and 7 deletions
|
@ -1,3 +1,11 @@
|
|||
2018-05-09 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
* include/bits/std_function.h (_Base_manager::_M_get_pointer):
|
||||
Use constexpr if in C++17 mode.
|
||||
(_Base_manager::_M_clone(_Any_data&, const _Any_data&, true_type)):
|
||||
Copy from const object.
|
||||
* testsuite/20_util/function/cons/non_copyconstructible.cc: New.
|
||||
|
||||
2018-05-08 François Dumont <fdumont@gcc.gnu.org>
|
||||
|
||||
* src/c++11/debug.cc [_GLIBCXX_HAVE_EXECINFO_H]: Include execinfo.h.
|
||||
|
|
|
@ -131,8 +131,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
class _Function_base
|
||||
{
|
||||
public:
|
||||
static const std::size_t _M_max_size = sizeof(_Nocopy_types);
|
||||
static const std::size_t _M_max_align = __alignof__(_Nocopy_types);
|
||||
static const size_t _M_max_size = sizeof(_Nocopy_types);
|
||||
static const size_t _M_max_align = __alignof__(_Nocopy_types);
|
||||
|
||||
template<typename _Functor>
|
||||
class _Base_manager
|
||||
|
@ -150,10 +150,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
static _Functor*
|
||||
_M_get_pointer(const _Any_data& __source)
|
||||
{
|
||||
const _Functor* __ptr =
|
||||
__stored_locally? std::__addressof(__source._M_access<_Functor>())
|
||||
/* have stored a pointer */ : __source._M_access<_Functor*>();
|
||||
return const_cast<_Functor*>(__ptr);
|
||||
if _GLIBCXX17_CONSTEXPR (__stored_locally)
|
||||
{
|
||||
const _Functor& __f = __source._M_access<_Functor>();
|
||||
return const_cast<_Functor*>(std::__addressof(__f));
|
||||
}
|
||||
else // have stored a pointer
|
||||
return __source._M_access<_Functor*>();
|
||||
}
|
||||
|
||||
// Clone a location-invariant function object that fits within
|
||||
|
@ -170,7 +173,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_M_clone(_Any_data& __dest, const _Any_data& __source, false_type)
|
||||
{
|
||||
__dest._M_access<_Functor*>() =
|
||||
new _Functor(*__source._M_access<_Functor*>());
|
||||
new _Functor(*__source._M_access<const _Functor*>());
|
||||
}
|
||||
|
||||
// Destroying a location-invariant object may still require
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library 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, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library 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 library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-do run { target c++11 } }
|
||||
|
||||
#include <functional>
|
||||
|
||||
// This type is not CopyConstructible because copying a non-const lvalue
|
||||
// will call the throwing constructor.
|
||||
struct A
|
||||
{
|
||||
A() = default;
|
||||
A(const A&) { } // not trivial, so allocated on the heap by std::function
|
||||
A(A&) { throw 1; }
|
||||
void operator()() const { }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
const A a{};
|
||||
// Undefined, because std::function requires CopyConstructible:
|
||||
std::function<void()> f(a);
|
||||
// This will throw if the object is copied as non-const:
|
||||
std::function<void()> g(f);
|
||||
}
|
Loading…
Add table
Reference in a new issue