[optional] problems with swap()

Hi Fernando, I have some comments on the way optional<T>::swap() is implemented. I looks like this: // optional's swap: // If both are initialized, calls swap(T&, T&). If this swap throws, //both will remain initialized but their values are now unspecified. // If only one is initialized, calls U.reset(*I), THEN I.reset(). // If U.reset(*I) throws, both are left UNCHANGED (U is kept //uinitialized and I is never reset) // If both are uninitialized, do nothing (no-throw) template<class T> inline void optional_swap ( optional<T>& x, optional<T>& y ) { if ( !x && !!y ) { x.reset(*y); y.reset(); } else if ( !!x && !y ) { y.reset(*x); x.reset(); } else if ( !!x && !!y ) { // GCC > 3.2 and all other compilers have the using declaration at function scope (FLC) #ifndef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE // allow for Koenig lookup using std::swap ; #endif swap(*x,*y); } } The problem here is that the two first cases do not delegate to the version of swap found by ADL. That only happens in cases where both objects are initialized. This is, AFAICT, a major problem because copy-construction has quite different semantics than swap() when it comes to invalidation of iterators or pointers. It works ok for ints, but creates havoc when using a container with internal memory. I suggest we do something along these lines: template<class T> inline void optional_swap ( optional<T>& x, optional<T>& y ) { bool hasX = x; bool hasY = y; if ( !hasX && !hasY ) return; if( !hasX ) x = boost::in_place(); else if ( !hasY ) y = boost::in_place(); // GCC > 3.2 and all other compilers have the using declaration at function scope (FLC) #ifndef BOOST_OPTIONAL_STD_SWAP_INTRODUCED_AT_NS_SCOPE // allow for Koenig lookup using std::swap ; #endif swap(*x,*y); if( !hasX ) y.reset(); else if( !hasY ) x.reset(); } Comments? -Thorsten

Thorsten Ottosen wrote:
Hi Fernando,
I have some comments on the way optional<T>::swap() is implemented. I looks like this:
// optional's swap: // If both are initialized, calls swap(T&, T&). If this swap throws, //both will remain initialized but their values are now unspecified. // If only one is initialized, calls U.reset(*I), THEN I.reset(). // If U.reset(*I) throws, both are left UNCHANGED (U is kept //uinitialized and I is never reset) // If both are uninitialized, do nothing (no-throw)
[snip]
The problem here is that the two first cases do not delegate to the version of swap found by ADL. That only happens in cases where both objects are initialized. This is, AFAICT, a major problem because copy-construction has quite different semantics than swap() when it comes to invalidation of iterators or pointers. It works ok for ints, but creates havoc when using a container with internal memory.
I suggest we do something along these lines:
[snip]
Comments?
Your approach requires the T to be default constructible which is not always the case. Besides, to my mind, the current implementation is more obvious for the user. Your behavior can be implemented in a non-intrusive way something like that: template< typename T > void force_koenig_swap(optional< T >& left, optional< T >& right) { bool left_empty = !left; if (left_empty) left = in_place(); bool right_empty = !right; if (right_empty) right = in_place(); using std::swap; swap(left.get(), right.get()); if (left_empty) right = none; if (right_empty) left = none; } As for optional, I think, move construction would be more appropriate in case if one of the optionals is empty. And if T does not support moving the current implementation is good enough.

Andrey Semashev skrev:
Thorsten Ottosen wrote:
Hi Fernando,
I have some comments on the way optional<T>::swap() is implemented. I looks like this:
// optional's swap: // If both are initialized, calls swap(T&, T&). If this swap throws, //both will remain initialized but their values are now unspecified. // If only one is initialized, calls U.reset(*I), THEN I.reset(). // If U.reset(*I) throws, both are left UNCHANGED (U is kept //uinitialized and I is never reset) // If both are uninitialized, do nothing (no-throw)
[snip]
The problem here is that the two first cases do not delegate to the version of swap found by ADL. That only happens in cases where both objects are initialized. This is, AFAICT, a major problem because copy-construction has quite different semantics than swap() when it comes to invalidation of iterators or pointers. It works ok for ints, but creates havoc when using a container with internal memory.
I suggest we do something along these lines:
[snip]
Comments?
Your approach requires the T to be default constructible which is not always the case.
Why is this better than the far more expensive copy-construction?
Besides, to my mind, the current implementation is more obvious for the user.
No user expects swap to throw or invalidate iterators or references like the current implementation does. -Thorsten

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Thursday 10 April 2008 16:02 pm, Thorsten Ottosen wrote:
Your approach requires the T to be default constructible which is not always the case.
Why is this better than the far more expensive copy-construction?
The documentation indicates optional<T> requires T to be copy constructible. It explicitly does not require T to be default constructible.
Besides, to my mind, the current implementation is more obvious for the user.
No user expects swap to throw or invalidate iterators or references like the current implementation does.
Personally, I consider any preservation of iterators/references/pointers to the internals of a swapped object to be purely a side-effect of a swap specialization, whose raise d'etre is as a speed optimization. - -- Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFH/n5V5vihyNWuA4URAr9RAJ4q7fodOLKbArYSBzTbosEwQHKWvACcDs8d AukOjKNmV5bJ70lp6ozcp8g= =zPA9 -----END PGP SIGNATURE-----

Frank Mori Hess skrev:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On Thursday 10 April 2008 16:02 pm, Thorsten Ottosen wrote:
Your approach requires the T to be default constructible which is not always the case. Why is this better than the far more expensive copy-construction?
The documentation indicates optional<T> requires T to be copy constructible. It explicitly does not require T to be default constructible.
Well, not all operations requries T to be copy-constructible, just as not all operations would require it to be default constructible.
Besides, to my mind, the current implementation is more obvious for the user. No user expects swap to throw or invalidate iterators or references like the current implementation does.
Personally, I consider any preservation of iterators/references/pointers to the internals of a swapped object to be purely a side-effect of a swap specialization, whose raise d'etre is as a speed optimization.
If speed is an issue, then the current implementation is also worse than what i suggested: copy construction + destruction is *far more expensive* than default construction + specialized swap + destruction for non-trivial classes with heap-based memory. The latter typically requires zero heap allocations. -Thorsten

Thorsten Ottosen wrote:
No user expects swap to throw or invalidate iterators or references like the current implementation does.
I do agree that it's a pity that the current implementation of optional::swap might throw an exception. Still, like Andrey Semashev, I'd rather not have it require T to be default constructible. Because I can imagine that people typically use optional<T> for a non-DefaultConstructible T. (A nice thing about boost::optional<T> is that it provides a default constructor, even for those types T that don't have one.) What would you think of having boost::optional implemented by holding a pointer to T, instead of an aligned_storage object and a m_initialized flag? It would manage the memory that the pointer would point to. Having NULL would indicate being uninitialized. (I admit it's a rather theoretical question, because I don't even know if Fernando would like such an approach...) Kind regards, -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center

Niels Dekker - mail address until 2008-12-31 skrev:
Thorsten Ottosen wrote:
No user expects swap to throw or invalidate iterators or references like the current implementation does.
I do agree that it's a pity that the current implementation of optional::swap might throw an exception. Still, like Andrey Semashev, I'd rather not have it require T to be default constructible. Because I can imagine that people typically use optional<T> for a non-DefaultConstructible T. (A nice thing about boost::optional<T> is that it provides a default constructor, even for those types T that don't have one.)
Right, this is certainly true, but this is not the same as "none of the functions in optional's interface can/should require default constructible".
What would you think of having boost::optional implemented by holding a pointer to T, instead of an aligned_storage object and a m_initialized flag? It would manage the memory that the pointer would point to. Having NULL would indicate being uninitialized. (I admit it's a rather theoretical question, because I don't even know if Fernando would like such an approach...)
Going for a heap based implementation is out of the question for performance reasons. -Thorsten

From: "Niels Dekker - mail address until 2008-12-31" <nd_mail_address_valid_until_2008-12-31@xs4all.nl> Subject: Re: [boost] [optional] problems with swap()
Thorsten Ottosen wrote: <snip>
What would you think of having boost::optional implemented by holding a pointer to T, instead of an aligned_storage object and a m_initialized flag? It would manage the memory that the pointer would point to. Having NULL would indicate being uninitialized. (I admit it's a rather theoretical question, because I don't even know if Fernando would like such an approach...)
I don't think that it is a good idea to have a pointer, I expect no extra allocation from optional. You can always try to do that in another class, optional_ptr or whatever name you want for. I think that this class will be very eassy to implement. Still I will expect value semantics, and in this case the extra allocation on copy constructors and assignations will be very inefficient. Best _____________________ Vicente Juan Botet Escriba

Thorsten Ottosen wrote:
Andrey Semashev skrev:
Thorsten Ottosen wrote:
Comments? Your approach requires the T to be default constructible which is not always the case.
Why is this better than the far more expensive copy-construction?
1. It adds a new requirement to T. I'd rather not have it since, as other noted, optional is frequently used with non-default-constructible types. You'll simply restrict swap to be available only for default-constructible types, which is not the case ATM. 2. I'd rather not assume what is more or less expensive. The opposite case is quite common too (shared pimpl object is an example).
Besides, to my mind, the current implementation is more obvious for the user.
No user expects swap to throw or invalidate iterators or references like the current implementation does.
Default constructor may throw as well, you won't gain anything here. And I'm not sure I understand what you meant with iterators or references invalidation.

Andrey Semashev skrev:
Thorsten Ottosen wrote:
Andrey Semashev skrev:
Thorsten Ottosen wrote:
Comments? Your approach requires the T to be default constructible which is not always the case. Why is this better than the far more expensive copy-construction?
1. It adds a new requirement to T.
But only for swap().
I'd rather not have it since, as other noted, optional is frequently used with non-default-constructible types. You'll simply restrict swap to be available only for default-constructible types, which is not the case ATM.
True.
2. I'd rather not assume what is more or less expensive. The opposite case is quite common too (shared pimpl object is an example).
In that case they are about the same complexity. But for any container or aggregation of containers, there is a huge difference. Just consider std::vector<std::map<int,int>>, for example.
Besides, to my mind, the current implementation is more obvious for the user. No user expects swap to throw or invalidate iterators or references like the current implementation does.
Default constructor may throw as well, you won't gain anything here.
Default constructors are much less likely to throw.
And I'm not sure I understand what you meant with iterators or references invalidation.
If I hold a reference or an iterator into, say a vector<T> object, that reference or iterator is not invalidated by swapping that object with another. For optional<vector<T>> this is no longer true. Anyway, I'll like to hear Fernando's take on it. -Thorsten

Thorsten Ottosen wrote:
Andrey Semashev skrev:
Thorsten Ottosen wrote:
Andrey Semashev skrev:
Your approach requires the T to be default constructible which is not always the case.
Why is this better than the far more expensive copy-construction?
1. It adds a new requirement to T.
But only for swap().
It's still a new requirement, which I find quite unacceptable. Suddenly I can't swap types without default constructors anymore? If this variant of swap() is really more efficient, perhaps metaprogramming could be used to support it *if* the type has a default constructor. But I don't know how to detect this. TypeTraits doesn't contain a has_default_constructor trait. It may be that this will only work with 09 concepts - DefaultConstructible. Sebastian

On Fri, Apr 11, 2008 at 9:38 AM, Sebastian Redl < sebastian.redl@getdesigned.at> wrote:
If this variant of swap() is really more efficient, perhaps metaprogramming could be used to support it *if* the type has a default constructor. But I don't know how to detect this. TypeTraits doesn't contain a has_default_constructor trait. It may be that this will only work with 09 concepts - DefaultConstructible.
We can use has_nothrow_default_constructor . This will also exclude the specialization when the default constructor performs some allocation, and could result in lower performance. Corrado
Sebastian _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Corrado Zoccolo skrev:
On Fri, Apr 11, 2008 at 9:38 AM, Sebastian Redl < sebastian.redl@getdesigned.at> wrote:
If this variant of swap() is really more efficient, perhaps metaprogramming could be used to support it *if* the type has a default constructor. But I don't know how to detect this. TypeTraits doesn't contain a has_default_constructor trait. It may be that this will only work with 09 concepts - DefaultConstructible.
We can use has_nothrow_default_constructor . This will also exclude the specialization when the default constructor performs some allocation, and could result in lower performance.
I can't imagine that it would result in lower performance in general ... have you seen many types for which default construction was more expensive than copy-construction? has_nothrow_default_constructor is certainly useable, albeit it requires compiler inrinsics. Do we know how many compilers that do support them? -Thorsten

Thorsten Ottosen wrote in his OP:
I have some comments on the way optional<T>::swap()
Hmmm... I can't find optional<T>::swap in my copy of optional.hpp (straight from the trunk)! It looks like optional<T> only has a non-member boost::swap function! I think it should definitely have a swap member function, as well! As a guideline, whenever providing a non-member swap function for a class type, one should provide a swap member function as well! (E.g., Scott Meyers, Effective C++ Third Edition, item 25!). Why? Because the STL does it that way, /and/ because it allows swapping a temporary. Of course, optional<T>::swap could be implemented very easily: void swap( optional & arg ) { using std::swap; swap(*this, arg); } By default, it would call the original boost::swap(optional<T>&, optional<T>&), by appying ADL. But it would also allow end users to customize the behavior of optional<T>::swap for their specific types, either by providing a template specialization of boost::swap or std::swap, or by adding an overloaded swap function to the namespace of T. Thorsten Ottosen wrote:
I can't imagine that it would result in lower performance in general ... have you seen many types for which default construction was more expensive than copy-construction?
Clearly if T has a nothrow default-constructor, it would make sense to use it, when swapping optional<T>. But otherwise it's hard to say "in general" what swap implementation is best for any optional<T>. In that case the user could still provide her own custom swap function for optional<T>, for her particular type T, as I just described. Wouldn't that solve the issue? Kind regards, Niels

On Saturday 12 April 2008 08:31, Niels Dekker - mail address until 2008-12-31 wrote:
Hmmm... I can't find optional<T>::swap in my copy of optional.hpp (straight from the trunk)! It looks like optional<T> only has a non-member boost::swap function! I think it should definitely have a swap member function, as well! As a guideline, whenever providing a non-member swap function for a class type, one should provide a swap member function as well! (E.g., Scott Meyers, Effective C++ Third Edition, item 25!). Why? Because the STL does it that way, /and/ because it allows swapping a temporary.
Of course, optional<T>::swap could be implemented very easily:
void swap( optional & arg ) { using std::swap; swap(*this, arg); }
By default, it would call the original boost::swap(optional<T>&, optional<T>&), by appying ADL. But it would also allow end users to customize the behavior of optional<T>::swap for their specific types, either by providing a template specialization of boost::swap or std::swap, or by adding an overloaded swap function to the namespace of T.
Maybe it was just my compiler, but I've had problems in the past with member swap functions breaking ADL for swap used inside the class. IIRC, it would find the member swap function and stop there, never doing ADL. -- Frank

Frank Mori Hess:
Maybe it was just my compiler, but I've had problems in the past with member swap functions breaking ADL for swap used inside the class. IIRC, it would find the member swap function and stop there, never doing ADL.
This is standard-conforming. You've forgotten the using std::swap declaration which reenables ADL by making a nonmember visible in the current scope.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Saturday 12 April 2008 12:03 pm, Peter Dimov wrote:
Frank Mori Hess:
Maybe it was just my compiler, but I've had problems in the past with member swap functions breaking ADL for swap used inside the class. IIRC, it would find the member swap function and stop there, never doing ADL.
This is standard-conforming. You've forgotten the using std::swap declaration which reenables ADL by making a nonmember visible in the current scope.
Ah, thanks for the tip. I must have left out the "using std::swap" because none of the swap calls I was using actually resolved to std::swap. - -- Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFIAPXu5vihyNWuA4URAv98AKDmECn413J00o5LNTXzTHDtuVo0tgCeML5/ FfJ8qqq6j2dUQkvoFpE6o5k= =1p5g -----END PGP SIGNATURE-----

On Saturday, 12 April, I suggested adding a swap member function to optional<T>:
optional<T>::swap could be implemented very easily:
void swap( optional & arg ) { using std::swap; swap(*this, arg); }
By default, it would call the original boost::swap(optional<T>&, optional<T>&), by appying ADL.
Fernando (the owner of Boost.Optional) has agreed, so I added the member function last Friday (trunk, changeset [44766]). Unfortunately some of the tests I added fail on previous versions of GCC (3.3.1, 3.4, 4.0.1): http://www.boost.org/development/tests/trunk/developer/optional_.html Apparently those compilers didn't apply ADL, and called std::swap instead! Luckily I have some ideas on how to fix it :-) First of all, when the compiler was processing the swap member function, it might not have seen optional<T>'s overload of boost::swap yet. Because boost::swap(optional<T>&, optional<T>&) was defined a few hundred lines /after/ the member function. Is the compiler allowed to ignore the overloaded boost::swap function (template) in this case, when applying ADL? Anyway, it's certainly helpful to those compilers to add a forward declaration: namespace boost { template<class T> void swap ( optional<T>& , optional<T>& ) ; } It looks like the forward file, "optional_fwd.hpp", is a proper place for such a forward declaration. Don't you think? Still this doesn't seem enough to get my copy of GCC (version 3.4.4, cygming special) to do ADL. It keeps calling std::swap! So instead of doing "using std::swap", I consider doing "using boost::swap": void swap( optional & arg ) { // allow for Koenig lookup using boost::swap ; swap(*this, arg); } In this particular case I guess, according to the Standard, there wouldn't be a semantic difference between "using boost::swap" and "using std::swap" anyway. Right? Note that optional's swap member function is still an "undocumented feature" (trunk only). When the tests are passed, I'll add a few lines of doc. Frank Mori Hess:
Maybe it was just my compiler, but I've had problems in the past with member swap functions breaking ADL for swap used inside the class. IIRC, it would find the member swap function and stop there, never doing ADL.
Peter Dimov wrote:
This is standard-conforming. You've forgotten the using std::swap declaration which reenables ADL by making a nonmember visible in the current scope.
Thanks! Luckily none of the tested compilers failed to /compile/ the member function, so "using std::swap" has certainly succeeded to make a nonmember swap visible in the scope of the member function definition. :-) Kind regards, Niels

On Sat, Apr 12, 2008 at 11:58 AM, Thorsten Ottosen < thorsten.ottosen@dezide.com> wrote:
Corrado Zoccolo skrev:
On Fri, Apr 11, 2008 at 9:38 AM, Sebastian Redl < sebastian.redl@getdesigned.at> wrote:
If this variant of swap() is really more efficient, perhaps metaprogramming could be used to support it *if* the type has a default constructor. But I don't know how to detect this. TypeTraits doesn't contain a has_default_constructor trait. It may be that this will only work with 09 concepts - DefaultConstructible.
We can use has_nothrow_default_constructor . This will also exclude the specialization when the default constructor performs some allocation, and could result in lower performance.
I can't imagine that it would result in lower performance in general ... have you seen many types for which default construction was more expensive than copy-construction?
For example shared-pimpl objects (mentioned by Andrey), will only increment a reference count on copy construction, but may need to allocate memory on default construction.
has_nothrow_default_constructor is certainly useable, albeit it requires compiler inrinsics. Do we know how many compilers that do support them?
I think boost could provide some specializations it for stl types that require it, and the user is allowed to specialize it for his types. I think variant has a similar optimization for exception safety purposes, that works under similar assumptions. Corrado
-Thorsten _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- __________________________________________________________________________ dott. Corrado Zoccolo mailto:zoccolo@di.unipi.it PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda

Hi Andrey,
Your behavior can be implemented in a non-intrusive way something like that:
template< typename T > void force_koenig_swap(optional< T >& left, optional< T >& right) { bool left_empty = !left; if (left_empty) left = in_place(); bool right_empty = !right; if (right_empty) right = in_place();
using std::swap; swap(left.get(), right.get());
if (left_empty) right = none; if (right_empty) left = none; }
But isn't that, syntax aside, *exactly* the same Thorsten proposed?? I can't tell the difference... Best -- Fernando Cacciola SciSoft http://fcacciola.50webs.com http://groups.google.com/group/cppba

Fernando Cacciola wrote:
Hi Andrey,
Your behavior can be implemented in a non-intrusive way something like that:
template< typename T > void force_koenig_swap(optional< T >& left, optional< T >& right) { bool left_empty = !left; if (left_empty) left = in_place(); bool right_empty = !right; if (right_empty) right = in_place();
using std::swap; swap(left.get(), right.get());
if (left_empty) right = none; if (right_empty) left = none; }
But isn't that, syntax aside, *exactly* the same Thorsten proposed?? I can't tell the difference...
The only difference is that it's not intrusive.

Hi Thorsten, Adding the new requirement is out of the question, but it's definitely possible to choose default construction or zero-initialization as appropiate. And IMO that magic would be best placed within boost::in_place() itself since it makes a lot of sense, given its nature, to do zero-initialization for non-default constructible types. With such a smart in_place factory, the optional swap implementation would look exactly as you proposed it AFAICT. Good job! Best -- Fernando Cacciola SciSoft http://fcacciola.50webs.com http://groups.google.com/group/cppba

Fernando Cacciola wrote:
Adding the new requirement is out of the question, but it's definitely possible to choose default construction or zero-initialization as appropiate. And IMO that magic would be best placed within boost::in_place() itself since it makes a lot of sense, given its nature, to do zero-initialization for non-default constructible types.
Please explain! Doesn't a call to boost::in_place(), having zero arguments, require T to be DefaultConstructible? Kind regards, Niels

Niels Dekker - mail address until 2008-12-31 wrote:
Fernando Cacciola wrote:
Adding the new requirement is out of the question, but it's definitely possible to choose default construction or zero-initialization as appropiate. And IMO that magic would be best placed within boost::in_place() itself since it makes a lot of sense, given its nature, to do zero-initialization for non-default constructible types.
Please explain! Doesn't a call to boost::in_place(), having zero arguments, require T to be DefaultConstructible?
I was posposing to remove that requirement to have it be zero-initialized instead... but don't listen to me. Is there a list with the worst ideas ever? I'd like to add this one ;) Now that I finally got that much needed jar of cofee: I do like Thorsten proposal even if the implementation must use type-traits to do that only when the type is default-constructible. Best Fernando Cacciola

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Friday 11 April 2008 15:00 pm, Fernando Cacciola wrote:
Hi Thorsten,
Adding the new requirement is out of the question, but it's definitely possible to choose default construction or zero-initialization as appropiate. And IMO that magic would be best placed within boost::in_place() itself since it makes a lot of sense, given its nature, to do zero-initialization for non-default constructible types.
With such a smart in_place factory, the optional swap implementation would look exactly as you proposed it AFAICT.
If I'm following, you're proposing calling swap on an object which doesn't really exist, but is just a zero'ed block of memory? Wouldn't that be undefined behavior? Suppose the template type contains a mutex and its swap specialization tries to lock the mutexes for both objects before swapping their contents. It would crash wouldn't it? - -- Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFH/81V5vihyNWuA4URAvTbAKDaYhtp2O7eeo150sscSRgcJ3VVFQCeNjvP dG2Px8pwBvZkHHOd7GGJvHo= =Qwdg -----END PGP SIGNATURE-----

Frank Mori Hess wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On Friday 11 April 2008 15:00 pm, Fernando Cacciola wrote:
Hi Thorsten,
Adding the new requirement is out of the question, but it's definitely possible to choose default construction or zero-initialization as appropiate. And IMO that magic would be best placed within boost::in_place() itself since it makes a lot of sense, given its nature, to do zero-initialization for non-default constructible types.
With such a smart in_place factory, the optional swap implementation would look exactly as you proposed it AFAICT.
If I'm following, you're proposing calling swap on an object which doesn't really exist, but is just a zero'ed block of memory? Wouldn't that be undefined behavior?
Yeap, it would... I'm writting nonsense already and the weekend haven't even started yet :) Best Fernando
participants (10)
-
Andrey Semashev
-
Corrado Zoccolo
-
Fernando Cacciola
-
Frank Mori Hess
-
Frank Mori Hess
-
Niels Dekker - mail address until 2008-12-31
-
Peter Dimov
-
Sebastian Redl
-
Thorsten Ottosen
-
vicente.botet