boost::scoped_array::release?

Does this patch for boost/scoped_array.hpp look useful? < T * release() // never throws < { < T * result = ptr; < ptr = 0; < return result; < } < It allows me to use boost::scoped_array almost like an auto_ptr: int* foo(size) { boost::scoped_array<int> result(new int[size]); // do something to result // if an exception is thrown result will be cleaned up return result.release(); } void bar() { boost::scoped_array<int> foo_result(foo(1000)); // code is still exception safe } I wouldn't need this if - we had std::auto_array (don't think it exists) - std::vector<int>(size) wouldn't do the default construction of all elements and I didn't care about having two pointers instead of just one (sometimes I actually do care) - boost::scoped_array::ptr was protected instead of private so that I could inherit and add release() Are there arguments for not adding release()? Cheers, Ralf __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

On 3/8/06, Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> wrote:
Are there arguments for not adding release()?
Check the FAQ on the scoped_ptr documentation. -- ------------------------------------------- Dan Day http://razzerblog.blogspot.com

--- Dan Day <coolmandan@gmail.com> wrote:
On 3/8/06, Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> wrote:
Are there arguments for not adding release()?
Check the FAQ on the scoped_ptr documentation.
Policing arguments ("you shouldn't to this") are OK only if there is an alternative. As I wrote before, there is no auto_array, therefore the FAQ is just frustrating. Ralf __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

On 3/9/06, Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> wrote:
Policing arguments ("you shouldn't to this") are OK only if there is an alternative. As I wrote before, there is no auto_array, therefore the FAQ is just frustrating.
If you want to use auto_array, you can. Either take an open source auto_ptr implementation and adapt it, or google for an existing implementation. A better solution might be to use Jonathan Turkanis' move_ptr library - which works for arrays. http://www.kangaroologic.com/move_ptr/ Daniel

Ralf W. Grosse-Kunstleve wrote:
--- Dan Day <coolmandan@gmail.com> wrote:
On 3/8/06, Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> wrote:
Are there arguments for not adding release()?
Check the FAQ on the scoped_ptr documentation.
Policing arguments ("you shouldn't to this") are OK only if there is an alternative. As I wrote before, there is no auto_array, therefore the FAQ is just frustrating.
I'm willing to add scoped_array::release if nobody objects and if you contribute a test. But keep in mind that 1.34 is closed for new features.

--- Peter Dimov <pdimov@mmltd.net> wrote:
Ralf W. Grosse-Kunstleve wrote:
--- Dan Day <coolmandan@gmail.com> wrote:
On 3/8/06, Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> wrote:
Are there arguments for not adding release()?
Check the FAQ on the scoped_ptr documentation.
Policing arguments ("you shouldn't to this") are OK only if there is an alternative. As I wrote before, there is no auto_array, therefore the FAQ is just frustrating.
I'm willing to add scoped_array::release if nobody objects and if you contribute a test. But keep in mind that 1.34 is closed for new features.
In the meantime I implemented auto_array, starting with the scoped_array implementation: http://phenix-online.org/cctbx_sources/scitbx/include/scitbx/auto_array.h For the future, eventually the same file should show up here with version history: http://cvs.sourceforge.net/viewcvs.py/cctbx/scitbx/include/scitbx/ In contrast to the STLport implementation I use this approach to implement the copy constructor (and similarly for the assignment operator): class auto_array { mutable T* ptr; auto_array(auto_array const& other) { ptr = const_cast<auto_array*>(&other)->release(); } }; I know it works on a large number of platforms (several versions of EDG, VC, g++). valgrind also didn't have any complaints. Is the approach also OK from a theoretical viewpoint? Or is it necessary to adopt the more involved STLport approach of introducing an auto_ptr_ref with a common base class for auto_ptr, auto_ptr_ref? I'd be happy to contribute my version back to boost. Then the FAQ wouldn't be frustrating anymore and scoped_array could stay as is. Cheers, Ralf __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

Ralf W. Grosse-Kunstleve wrote:
In contrast to the STLport implementation I use this approach to implement the copy constructor (and similarly for the assignment operator):
class auto_array { mutable T* ptr;
auto_array(auto_array const& other) { ptr = const_cast<auto_array*>(&other)->release(); } };
I know it works on a large number of platforms (several versions of EDG, VC, g++). valgrind also didn't have any complaints. Is the approach also OK from a theoretical viewpoint?
I don't know about STLport's approach, but const-casting the parameter is definitely not OK from a theoretical viewpoint. Your const parameter is a promise that you won't modify the parameter, but then you go ahead and do it anyway. You should make the parameter non-const, like the GNU C++ library does with auto_ptr: auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { } Sebastian Redl

--- Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
I know it works on a large number of platforms (several versions of EDG, VC, g++). valgrind also didn't have any complaints. Is the approach also OK from a theoretical viewpoint?
I don't know about STLport's approach, but const-casting the parameter is definitely not OK from a theoretical viewpoint.
OK, but my question was more: is my approach backed up by the ISO standard, or does it work just by chance?
Your const parameter is a promise that you won't modify the parameter, but then you go ahead and do it anyway. You should make the parameter non-const, like the GNU C++ library does with auto_ptr: auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }
The problem is that my code doesn't compile (g++ 3.4.2) if I remove the "const". I've tried adding the throw() but that didn't do it. I see there is also an auto_ptr_ref<> in the g++ library, but I don't know if this is what does the trick. Could one of the C++ gurus please explain? BTW: Assuming that I can get my auto_array to work without the const, in the copy constructor and assignment operator, what is the difference between const auto_array<T> and scoped_array<T> ? Apart from the release() it looks almost the same. Ralf __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

On Friday 10 March 2006 00:12, Ralf W. Grosse-Kunstleve wrote:
--- Sebastian Redl <sebastian.redl@getdesigned.at> wrote:
Your const parameter is a promise that you won't modify the parameter, but then you go ahead and do it anyway. You should make the parameter non-const, like the GNU C++ library does with auto_ptr: auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }
The problem is that my code doesn't compile (g++ 3.4.2) if I remove the "const". I've tried adding the throw() but that didn't do it. I see there is also an auto_ptr_ref<> in the g++ library, but I don't know if this is what does the trick. Could one of the C++ gurus please explain?
The problem is that if a function returns an object, that object is not an lvalue and thus doesn't bind to a non-const reference - therefore, you can't initialise another of your smart pointers with it. auto_ptr recognises that problem and provides a conversion to an auto_ptr_ref and a constructor taking an auto_ptr_ref. In other words, this auto_ptr_ref builds a bridge between the two auto_ptrs. I think there are at least two ways this is implemented, either by storing the raw pointer from release() inside the auto_ptr_ref or by storing a pointer to the auto_ptr inside it. I'm not sure if it makes much difference, I consider auto_ptr_ref an implementation detail anyways, even though the standard does define it. Just curious, but is there a valid reason to use auto_ptr_ref directly? Uli

On 3/9/06, Peter Dimov <pdimov@mmltd.net> wrote:
I'm willing to add scoped_array::release if nobody objects and if you contribute a test. But keep in mind that 1.34 is closed for new features.
My feeling is that, since scoped_ptr doesn't have release, scoped_array shouldn't either. It seems to me that the whole point of scoped_* is that the ownership cannot be moved elsewhere. Though that would suggest adding auto_array, which is something whose use shouldn't be encouraged, imho... ~ SWMc

me22 wrote:
My feeling is that, since scoped_ptr doesn't have release, scoped_array shouldn't either. It seems to me that the whole point of scoped_* is that the ownership cannot be moved elsewhere.
I agree. I use both of these classes for 2 reasons: (1) they delete their objects in any case that they go out of scope (exceptions, too); and (2) I don't have to worry about anyone writing code that will circumvent this behavior (and produce a bug or leak that I will have to find). Please, don't change the behavior of either of these simple and valuable classes. If someone wants anything to change, create a new class or subclass with a different name. -- Dick Hadsell 914-259-6320 Fax: 914-259-6499 Reply-to: hadsell@blueskystudios.com Blue Sky Studios http://www.blueskystudios.com 44 South Broadway, White Plains, NY 10601

--- me22 <me22.ca@gmail.com> wrote:
Though that would suggest adding auto_array, which is something whose use shouldn't be encouraged, imho...
Could you please explain why? What is your solution for the situation in my original posting? Here it is again, this time with auto_array: auto_array<int> foo(unsigned size) { auto_array<int> result(new int[size]); // do something to result // if an exception is thrown result will be cleaned up return result; } void bar() { auto_array<int> foo_result(foo(1000)); // code is still exception safe } Note that I don't want reference counting overhead (shared_array) or the overhead associated with std::vector (two pointers instead of just one, default construction on resize or lots of push_backs, deepcopy semantics). Ralf __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

On Mar 9, 2006, at 6:21 PM, Ralf W. Grosse-Kunstleve wrote:
--- me22 <me22.ca@gmail.com> wrote:
Though that would suggest adding auto_array, which is something whose use shouldn't be encouraged, imho...
Could you please explain why?
What is your solution for the situation in my original posting? Here it is again, this time with auto_array:
auto_array<int> foo(unsigned size) { auto_array<int> result(new int[size]); // do something to result // if an exception is thrown result will be cleaned up return result; }
void bar() { auto_array<int> foo_result(foo(1000)); // code is still exception safe }
Note that I don't want reference counting overhead (shared_array) or the overhead associated with std::vector (two pointers instead of just one, default construction on resize or lots of push_backs, deepcopy semantics).
Point your vendor at: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/ n1856.html#Addition%20-%20Class%20template%20unqiue_ptr and tell them you want it sooner rather than later. And now I'll be really embarrassed if your vendor is me. :-) But if it is, rattle my cage nonetheless! :-) According to this proposal your code would be: std::unique_ptr<int[]> foo(unsigned size) { std::unique_ptr<int[]> result(new int[size]); // do something to result // if an exception is thrown result will be cleaned up return result; } void bar() { std::unique_ptr<int[]> foo_result(foo(1000)); // code is still exception safe } In bar() (and foo()) you could access foo_result like: foo_result[i] but not like: *foo_result If you attempted a derived to base conversion: std::unique_ptr<D[]> foo(unsigned); void bar { std::unique_ptr<B[]> result(foo(N)); ... } then you would be stopped at compile time (C++ standard 5.3.5p3). And release() is part of the package too. Indeed, the existence of release() is the main advantage of unique_ptr<int[]> over vector<int> in this proposal. The same proposal will give you shallow copy semantics for vector as well. std::vector<int> foo(unsigned size) { std:: vector<int> result(size); // do something to result // if an exception is thrown result will be cleaned up return result; } void bar() { std::vector<int> foo_result(foo(1000)); // no deep copy of vector possible // code is still exception safe } From a practical point of view, I'm not sure any compiler today will fail to do RVO in this latter example, as long as there is only one return statement in foo() that unambiguously refers to only one vector declaration with auto storage (RVO is "perfect shallow copying"). If there are multiple returns referring to different (auto storage) vectors, then RVO will likely be defeated, but the referenced proposal will still result in an O(1) copy of the vector out of foo. -Howard

--- Howard Hinnant <howard.hinnant@gmail.com> wrote:
Note that I don't want reference counting overhead (shared_array) or the overhead associated with std::vector (two pointers instead of just one, default construction on resize or lots of push_backs, deepcopy semantics).
Point your vendor at:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/ n1856.html#Addition%20-%20Class%20template%20unqiue_ptr
and tell them you want it sooner rather than later.
Thanks for the link! unique_ptr looks like the best general solution. Problem is, I needed it yesterday (literally) and in fact I would have loved to use it many times before. If auto_ptr is going to be deprecated, of course auto_array shouldn't be in boost. How about this tiny patch then to keep poor old scientific application developers like me going until the optimal solution is universally available? Index: scoped_array.hpp =================================================================== RCS file: /cvsroot/boost/boost/boost/scoped_array.hpp,v retrieving revision 1.16 diff -u -r1.16 scoped_array.hpp --- scoped_array.hpp 19 Aug 2004 15:23:46 -0000 1.16 +++ scoped_array.hpp 10 Mar 2006 07:12:35 -0000 @@ -37,10 +37,12 @@ template<class T> class scoped_array // noncopyable { -private: +protected: T * ptr; +private: + scoped_array(scoped_array const &); scoped_array & operator=(scoped_array const &); Those in danger of abusing release() most likely won't notice that they can inherit, implement release() in the sub-class, and only then start abusing. But I'd be a happy chap because I wouldn't have to copy scoped_array.hpp wholesale. BTW: The scoped_ptr FAQ should be changed to point to the unique_ptr page. Otherwise people like me will keep thinking auto_ptr is a good thing. Thanks! Cheers, Ralf __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

On Mar 10, 2006, at 2:25 AM, Ralf W. Grosse-Kunstleve wrote:
Point your vendor at:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/ n1856.html#Addition%20-%20Class%20template%20unqiue_ptr
and tell them you want it sooner rather than later.
Thanks for the link! unique_ptr looks like the best general solution. Problem is, I needed it yesterday (literally) and in fact I would have loved to use it many times before.
If auto_ptr is going to be deprecated, of course auto_array shouldn't be in boost. How about this tiny patch then to keep poor old scientific application developers like me going until the optimal solution is universally available?
Another option is here: http://www.kangaroologic.com/move_ptr/ static_move_ptr is roughly a C++03 emulation of the proposed unique_ptr. -Howard

Another option is here: http://www.kangaroologic.com/move_ptr/
static_move_ptr is roughly a C++03 emulation of the proposed unique_ptr.
This static_move_ptr has an advantage I tried to emulate with boost::shmem::scoped_ptr (in the future boost::interprocess::scoped_ptr), which also has a template argument for the deleter (a must to free a shared memory portion allocated with buffer) and a "release" member. This allows user defined rollback functions using the deleter. You surely can do this with shared_ptr, but sometimes allocating the reference count is an overkill. I would suggest adding a templatized deleter for scoped_ptr (we don't always need "operator delete" to erase a pointer) or creating a templatized basic_scoped_ptr. The "release" member is in my opinion a good addition to allow rollback semantics (although implementing rollback functors as scoped_ptr deleters is a bit hard, even with bind/lambda). We can propose a rollback_ptr for this if we don't want to change scoped_ptr, although Andrei Alexandrescu's suggestion (on_block_xxx) would be optimal. Regards, Ion

On Mar 10, 2006, at 3:40 PM, Ion Gaztañaga wrote:
Another option is here: http://www.kangaroologic.com/move_ptr/
static_move_ptr is roughly a C++03 emulation of the proposed unique_ptr.
This static_move_ptr has an advantage I tried to emulate with boost::shmem::scoped_ptr (in the future boost::interprocess::scoped_ptr), which also has a template argument for the deleter (a must to free a shared memory portion allocated with buffer) and a "release" member.
This allows user defined rollback functions using the deleter. You surely can do this with shared_ptr, but sometimes allocating the reference count is an overkill.
I would suggest adding a templatized deleter for scoped_ptr (we don't always need "operator delete" to erase a pointer) or creating a templatized basic_scoped_ptr. The "release" member is in my opinion a good addition to allow rollback semantics (although implementing rollback functors as scoped_ptr deleters is a bit hard, even with bind/lambda). We can propose a rollback_ptr for this if we don't want to change scoped_ptr, although Andrei Alexandrescu's suggestion (on_block_xxx) would be optimal.
Or just accept static_move_ptr into boost? -Howard

Or just accept static_move_ptr into boost?
Right. If we can define the pointer type via deleter::pointer or similar (with default T*) that would be even better. I don't see move_ptr in the review schedule, but the documentation is nearly complete. Jonathan, do you plan to submit it? Ion

--- Howard Hinnant <howard.hinnant@gmail.com> wrote:
According to this proposal your code would be:
std::unique_ptr<int[]> foo(unsigned size) { std::unique_ptr<int[]> result(new int[size]); // do something to result // if an exception is thrown result will be cleaned up return result; }
Hi Howard, I fetched your emulation code and tried to compile the function above; the only change I made was to put your entire file into my own namespace (instead of std::). Both EDG 245 and gcc 3.4 give similar errors: cxx: Error: /net/legless/scratch1/rwgk/dist/iotbx/include/iotbx/pdb/input.h, line 1035: #330-D "scitbx::unique_ptr<T [], D>::unique_ptr(scitbx::unique_ptr<T [], D> &) [with T=int, D=scitbx::default_delete<int []>]" is inaccessible return result; -----------^ Is this an oversight, or do I have to use unique_ptr<> somehow differently? Thanks! Cheers, Ralf __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

On Mar 14, 2006, at 2:04 AM, Ralf W. Grosse-Kunstleve wrote:
--- Howard Hinnant <howard.hinnant@gmail.com> wrote:
According to this proposal your code would be:
std::unique_ptr<int[]> foo(unsigned size) { std::unique_ptr<int[]> result(new int[size]); // do something to result // if an exception is thrown result will be cleaned up return result; }
Hi Howard, I fetched your emulation code and tried to compile the function above; the only change I made was to put your entire file into my own namespace (instead of std::). Both EDG 245 and gcc 3.4 give similar errors:
cxx: Error: /net/legless/scratch1/rwgk/dist/iotbx/include/iotbx/pdb/ input.h, line 1035: #330-D "scitbx::unique_ptr<T [], D>::unique_ptr (scitbx::unique_ptr<T [], D> &) [with T=int, D=scitbx::default_delete<int []>]" is inaccessible return result; -----------^
Is this an oversight, or do I have to use unique_ptr<> somehow differently?
Hi Ralf, This is one of the areas where the emulated version is a little different from the real deal. You can work around this in one of two ways: unique_ptr<int[]> foo(unsigned size) { unique_ptr<int[]> result(new int[size]); // do something to result // if an exception is thrown result will be cleaned up return move(result); } or: unique_ptr<int[]> foo(unsigned size) { return unique_ptr<int[]>(new int[size]); } The move() effectively turns result into an rvalue which can then be moved from. In the move proposal the C++ language is changed such that expressions subject to RVO are implicitly treated as rvalues. Hope this helps. -Howard

--- Howard Hinnant <howard.hinnant@gmail.com> wrote:
This is one of the areas where the emulated version is a little different from the real deal. You can work around this in one of two ways:
unique_ptr<int[]> foo(unsigned size) { unique_ptr<int[]> result(new int[size]); // do something to result // if an exception is thrown result will be cleaned up return move(result); }
The additional move() does the trick for gcc 3.4 and EDG 245. Thanks! Unfortunately EDG 238 chokes (enable_if_does_not_work_on_this_compiler<T>) and gcc 2.96 gives an ICE. I'd be ready to finally give up on gcc 2.96, but EDG 238 is still important (sigh). I'll have to stick to my quick-and-dirty, old-fashioned auto_array emulation for the time being. Cheers, Ralf __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

I just dug this up from the archives. On 3/9/06, Peter Dimov <pdimov@mmltd.net> wrote:
Ralf W. Grosse-Kunstleve wrote:
--- Dan Day <coolmandan@gmail.com> wrote:
On 3/8/06, Ralf W. Grosse-Kunstleve <rwgk@yahoo.com> wrote:
Are there arguments for not adding release()?
Check the FAQ on the scoped_ptr documentation.
Policing arguments ("you shouldn't to this") are OK only if there is an alternative. As I wrote before, there is no auto_array, therefore the FAQ is just frustrating.
I'm willing to add scoped_array::release if nobody objects and if you contribute a test. But keep in mind that 1.34 is closed for new features.
Peter, did you ever add release to scoped_array? Did you get any objections (I did find, from scanning archives) that there were some detractors when this has come up before. But this seemed to mostly boil down to consistency - with some talking about having auto_array. The thread I cite here was about auto_array, and I think the OP actually wanted auto_ptr-like move semantics - but in many cases its just the release that is wanted. If there is a version of auto_array, or unique_ptr, or something - that will let me manage a raw array, with the ability to release ownership - that is already in Boost (or will be in the next version) then I'd be happy. Otherwise what are the chances of reopening the scoped_array::release() debate? Best regards, [)o IhIL..
participants (11)
-
Dan Day
-
Daniel James
-
Howard Hinnant
-
Ion Gaztañaga
-
me22
-
Peter Dimov
-
Phil Nash
-
Ralf W. Grosse-Kunstleve
-
Richard Hadsell
-
Sebastian Redl
-
Ulrich Eckhardt