Fixed undefined behavior in swap and assign.

[SVN r368]
This commit is contained in:
Eric Friedman
2002-08-08 09:40:13 +00:00
parent df2aaaf1e8
commit ff3246e479
2 changed files with 0 additions and 181 deletions

View File

@@ -1,80 +0,0 @@
//-----------------------------------------------------------------------------
// boost utility/safe_assign.hpp header file
// See http://www.boost.org for updates, documentation, and revision history.
//-----------------------------------------------------------------------------
//
// Copyright (c) 2002
// Eric Friedman
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appears in all copies and
// that both the copyright notice and this permission notice appear in
// supporting documentation. No representations are made about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
#ifndef BOOST_UTILITY_SAFE_ASSIGN_HPP
#define BOOST_UTILITY_SAFE_ASSIGN_HPP
#include "boost/utility/addressof.hpp"
#include "boost/type_traits/alignment_of.hpp"
// The following are new/in-progress headers or fixes to existing headers:
#include "boost/aligned_storage.hpp"
namespace boost {
// safe_assign
// Generic assignment w/ strong exception-safety guarantee.
//
// Rationale:
// safe_assign is more efficient than safe_swap for assignment.
//
// !WARNING!
// safe_assign CANNOT be safely used in the general case if the
// destination argument's data members may be accessed
// concurrently.
template <typename Destination, typename Source>
Destination& safe_assign(Destination& dest, const Source& src)
{
typedef aligned_storage<
sizeof(Destination)
, alignment_of<Destination>::value
> aligned_storage_t;
// Cache (for convienence) the addresses of lhs and rhs using addressof:
Destination* address = boost::addressof(dest);
// Now backup dest...
aligned_storage_t backup;
backup.memcpy_in(address);
try
{
// ...and attempt to overwrite dest with a (possible converted) copy of src:
new(address) Destination(src);
}
catch (...)
{
// In case of failure, restore dest using backup, and rethrow:
backup.memcpy_out(address);
throw;
}
// Since the copy succeeded, copy dest's new value off to the side,
// and (temporarily) restore dest's old value using backup:
aligned_storage_t new_value;
new_value.memcpy_in(address);
// Now destroy dest (which currently contains its _old_ value)...
dest.~Destination();
// ...and finally copy in its new (assigned) value:
new_value.memcpy_out(address);
return dest;
}
} // namespace boost
#endif // BOOST_UTILITY_SAFE_ASSIGN_HPP

View File

@@ -1,101 +0,0 @@
//-----------------------------------------------------------------------------
// boost utility/safe_swap.hpp header file
// See http://www.boost.org for updates, documentation, and revision history.
//-----------------------------------------------------------------------------
//
// Copyright (c) 2002
// Eric Friedman
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appears in all copies and
// that both the copyright notice and this permission notice appear in
// supporting documentation. No representations are made about the
// suitability of this software for any purpose. It is provided "as is"
// without express or implied warranty.
#ifndef BOOST_UTILITY_SAFE_SWAP_HPP
#define BOOST_UTILITY_SAFE_SWAP_HPP
#include "boost/utility/addressof.hpp"
#include "boost/type_traits/alignment_of.hpp"
// The following are new/in-progress headers or fixes to existing headers:
#include "boost/aligned_storage.hpp"
namespace boost {
// safe_swap
// Generic swap w/ strong exception-safety guarantee.
//
// !WARNING!
// safe_swap CANNOT be safely used in the general case if either
// argument's data members may be accessed concurrently.
template <typename T>
void safe_swap(T& lhs, T& rhs)
{
typedef aligned_storage<
sizeof(T)
, alignment_of<T>::value
> aligned_storage_t;
// Cache (for convienence) the addresses of lhs and rhs using addressof:
T* lhs_address = boost::addressof(lhs);
T* rhs_address = boost::addressof(rhs);
// Now backup lhs...
aligned_storage_t lhs_backup;
lhs_backup.memcpy_in(lhs_address);
try
{
// ...and attempt to overwrite lhs with a copy of rhs:
new(lhs_address) T(rhs);
}
catch (...)
{
// In event of error, restore lhs using backup, and rethrow:
lhs_backup.memcpy_out(lhs_address);
throw;
}
// Since the copy succeeded, copy lhs's new value off to the side,
// and (temporarily) restore lhs's old value using backup:
aligned_storage_t lhs_new;
lhs_new.memcpy_in(lhs_address);
lhs_backup.memcpy_out(lhs_address);
// Now backup rhs...
aligned_storage_t rhs_backup;
rhs_backup.memcpy_in(rhs_address);
try
{
// ...and attempt to overwrite rhs with a copy of lhs:
new(rhs_address) T(lhs);
}
catch (...)
{
// In event of error, restore rhs using backup, and rethrow:
rhs_backup.memcpy_out(rhs_address);
throw;
}
// Since the copy succeeded, copy rhs's new value off to the side,
// and (temporarily) restore rhs's old value using backup:
aligned_storage_t rhs_new;
rhs_new.memcpy_in(rhs_address);
rhs_backup.memcpy_out(rhs_address);
// Now destroy lhs and rhs (which currently contain their _old_ values)...
lhs.~T();
rhs.~T();
// ...and finally copy in their new (swapped) values:
lhs_new.memcpy_out(lhs_address);
rhs_new.memcpy_out(rhs_address);
}
} // namespace boost
#endif // BOOST_UTILITY_SAFE_SWAP_HPP