[Container] Inner Smart Pointers
I have to admit MSVC 2015 got a clean STL... block_ptr_test2.cpp doesn't crash but some assertions are wrong (in my block_ptr tests). Is there any plans from Boost to make the Boost.Container work with inner smart pointers? I don't think there is any other alternative if people want to plugin memory management. Thanks, -Phil
AMDG On 02/19/2016 05:53 PM, Phil Bouchard wrote:
On 2016-02-18 11:53 PM, Phil Bouchard wrote:
I have to admit MSVC 2015 got a clean STL...
Their STL is good but unfortunately they pass their pointer arguments by value and not by reference so it makes it impossible to use smart pointers for internal node pointers.
I don't understand how pass-by-value would break smart pointers. I can see that it might be inefficient, but it shouldn't actually fail. In Christ, Steven Watanabe
On 2016-02-19 9:30 PM, Steven Watanabe wrote:
AMDG
On 02/19/2016 05:53 PM, Phil Bouchard wrote:
On 2016-02-18 11:53 PM, Phil Bouchard wrote:
I have to admit MSVC 2015 got a clean STL...
Their STL is good but unfortunately they pass their pointer arguments by value and not by reference so it makes it impossible to use smart pointers for internal node pointers.
I don't understand how pass-by-value would break smart pointers. I can see that it might be inefficient, but it shouldn't actually fail.
Because the only way to deallocate the content of a smart pointer is by
deallocating and resetting its pointer to 0, which modifies the pointer.
For example:
1) The allocator's deallocate function will call p.reset():
template
AMDG On 02/19/2016 07:48 PM, Phil Bouchard wrote:
On 2016-02-19 9:30 PM, Steven Watanabe wrote:
On 02/19/2016 05:53 PM, Phil Bouchard wrote:
On 2016-02-18 11:53 PM, Phil Bouchard wrote:
I have to admit MSVC 2015 got a clean STL...
Their STL is good but unfortunately they pass their pointer arguments by value and not by reference so it makes it impossible to use smart pointers for internal node pointers.
I don't understand how pass-by-value would break smart pointers. I can see that it might be inefficient, but it shouldn't actually fail.
Because the only way to deallocate the content of a smart pointer is by deallocating and resetting its pointer to 0, which modifies the pointer.
For example:
1) The allocator's deallocate function will call p.reset():
<snip> 2) In MSVC 2015 the deallocate function is called by this one which has a pointer passed by value:
template<class _Alloc> struct _Wrap_alloc : public _Alloc { // defines traits for allocators [...] void deallocate(pointer _Ptr, size_type _Count) { // deallocate object at _Ptr, ignore size _Mybase::deallocate(_Ptr, _Count); }
That isn't specific to MSVC: [allocator.requirements]: Table 27: "p a value of type XX::pointer, obtained by calling a1.allocate, where a1 == a Table 28: "a.deallocate(p,n)" p is not required to be an lvalue, here. [allocator.members]: "void deallocate(pointer p, size_type n);" (C++11)
3) Which in turn is called by another one using a parameter passed by value:
template<class _Alloc_types> class _List_alloc { // base class for list to hold allocator public: [...] void _Freeheadnode(_Nodeptr _Pnode) { // free head node using current allocator _Getal().destroy( _STD addressof(_Nextnode(_Pnode))); _Getal().destroy( _STD addressof(_Prevnode(_Pnode))); _Getal().deallocate(_Pnode, 1); }
4) ...
The bottom line is resetting a copy of a smart pointer won't do anything. This is why it needs to be passed by reference.
You can't deallocate anything, anyway, because there may be other copies of the pointer. The whole point of using smart pointers in the first place, is that the deallocate is run automatically. Just leave allocator.deallocate as a no-op and let the memory be freed when the pointer is destroyed or assigned. In Christ, Steven Watanabe
On 2016-02-20 1:11 AM, Steven Watanabe wrote:
AMDG
On 02/19/2016 07:48 PM, Phil Bouchard wrote:
On 2016-02-19 9:30 PM, Steven Watanabe wrote:
On 02/19/2016 05:53 PM, Phil Bouchard wrote:
On 2016-02-18 11:53 PM, Phil Bouchard wrote:
I have to admit MSVC 2015 got a clean STL...
Their STL is good but unfortunately they pass their pointer arguments by value and not by reference so it makes it impossible to use smart pointers for internal node pointers.
I don't understand how pass-by-value would break smart pointers. I can see that it might be inefficient, but it shouldn't actually fail.
Because the only way to deallocate the content of a smart pointer is by deallocating and resetting its pointer to 0, which modifies the pointer.
For example:
1) The allocator's deallocate function will call p.reset():
<snip> 2) In MSVC 2015 the deallocate function is called by this one which has a pointer passed by value:
template<class _Alloc> struct _Wrap_alloc : public _Alloc { // defines traits for allocators [...] void deallocate(pointer _Ptr, size_type _Count) { // deallocate object at _Ptr, ignore size _Mybase::deallocate(_Ptr, _Count); }
That isn't specific to MSVC: [allocator.requirements]:
Table 27: "p a value of type XX::pointer, obtained by calling a1.allocate, where a1 == a
Table 28: "a.deallocate(p,n)"
p is not required to be an lvalue, here.
[allocator.members]: "void deallocate(pointer p, size_type n);"
(C++11)
3) Which in turn is called by another one using a parameter passed by value:
template<class _Alloc_types> class _List_alloc { // base class for list to hold allocator public: [...] void _Freeheadnode(_Nodeptr _Pnode) { // free head node using current allocator _Getal().destroy( _STD addressof(_Nextnode(_Pnode))); _Getal().destroy( _STD addressof(_Prevnode(_Pnode))); _Getal().deallocate(_Pnode, 1); }
4) ...
The bottom line is resetting a copy of a smart pointer won't do anything. This is why it needs to be passed by reference.
You can't deallocate anything, anyway, because there may be other copies of the pointer. The whole point of using smart pointers in the first place, is that the deallocate is run automatically. Just leave allocator.deallocate as a no-op and let the memory be freed when the pointer is destroyed or assigned.
I think you're right, thanks for the hint!
On 2016-02-18 11:53 PM, Phil Bouchard wrote:
I have to admit MSVC 2015 got a clean STL...
block_ptr_test2.cpp doesn't crash but some assertions are wrong (in my block_ptr tests).
Is there any plans from Boost to make the Boost.Container work with inner smart pointers? I don't think there is any other alternative if people want to plugin memory management.
After trying out to integrate the smart pointer into the MSVC's STL, it looks like they use raw node pointers so I don't think it'll be possible to do that after all. Is there any interests to modify the Boost.Container to use smart pointers? Thanks, -Phil
On 23/02/2016 4:20, Phil Bouchard wrote:
On 2016-02-18 11:53 PM, Phil Bouchard wrote:
I have to admit MSVC 2015 got a clean STL...
block_ptr_test2.cpp doesn't crash but some assertions are wrong (in my block_ptr tests).
Is there any plans from Boost to make the Boost.Container work with inner smart pointers? I don't think there is any other alternative if people want to plugin memory management.
After trying out to integrate the smart pointer into the MSVC's STL, it looks like they use raw node pointers so I don't think it'll be possible to do that after all.
Is there any interests to modify the Boost.Container to use smart pointers?
Boost.Container already uses whatever pointer allocator_traits<A>::pointer returns. That's the standard customization point for smart pointers in containers. Ion
On 2016-02-23 6:19 AM, Ion Gaztañaga wrote:
On 23/02/2016 4:20, Phil Bouchard wrote:
On 2016-02-18 11:53 PM, Phil Bouchard wrote:
I have to admit MSVC 2015 got a clean STL...
block_ptr_test2.cpp doesn't crash but some assertions are wrong (in my block_ptr tests).
Is there any plans from Boost to make the Boost.Container work with inner smart pointers? I don't think there is any other alternative if people want to plugin memory management.
After trying out to integrate the smart pointer into the MSVC's STL, it looks like they use raw node pointers so I don't think it'll be possible to do that after all.
Is there any interests to modify the Boost.Container to use smart pointers?
Boost.Container already uses whatever pointer allocator_traits<A>::pointer returns. That's the standard customization point for smart pointers in containers.
Ok thanks but I would still suggest to use references to pointer arguments, that would improve efficiency. I added minimalistic support for allocator_traits and pointer_traits and in trying to compile the following file with MSVC 2015: https://github.com/philippeb8/block_ptr/blob/master/example/block_ptr_test2.... I still have 3 compilation errors which aren't so obvious to figure out... Once again I use the following preprocessor definitions: BOOST_DISABLE_THREADS;_ITERATOR_DEBUG_LEVEL=0. block_ptr is getting more robust and I hope to make it bullet proof soon. Thanks, -Phil
On 2016-02-23 11:34 PM, Phil Bouchard wrote:
On 2016-02-23 6:19 AM, Ion Gaztañaga wrote:
On 23/02/2016 4:20, Phil Bouchard wrote:
On 2016-02-18 11:53 PM, Phil Bouchard wrote:
I have to admit MSVC 2015 got a clean STL...
block_ptr_test2.cpp doesn't crash but some assertions are wrong (in my block_ptr tests).
Is there any plans from Boost to make the Boost.Container work with inner smart pointers? I don't think there is any other alternative if people want to plugin memory management.
After trying out to integrate the smart pointer into the MSVC's STL, it looks like they use raw node pointers so I don't think it'll be possible to do that after all.
Is there any interests to modify the Boost.Container to use smart pointers?
Boost.Container already uses whatever pointer allocator_traits<A>::pointer returns. That's the standard customization point for smart pointers in containers.
Ok thanks but I would still suggest to use references to pointer arguments, that would improve efficiency.
I added minimalistic support for allocator_traits and pointer_traits and in trying to compile the following file with MSVC 2015: https://github.com/philippeb8/block_ptr/blob/master/example/block_ptr_test2....
I still have 3 compilation errors which aren't so obvious to figure out... Once again I use the following preprocessor definitions: BOOST_DISABLE_THREADS;_ITERATOR_DEBUG_LEVEL=0.
If I compile under Cygwin: g++ block_ptr_test2.cpp -fpermissive -std=c++11 -D__i386__ -DBOOST_DISABLE_THREADS -I ... I get a few errors as well. I am not sure which API gets it wrong.
On 2016-02-24 8:36 AM, Phil Bouchard wrote:
I get a few errors as well. I am not sure which API gets it wrong.
Ok I was able to fix the compilation, now I got run-time problems...
1) But I had to comment the default constructor of list_node public:
template
On 2016-02-25 8:38 PM, Rob Stewart wrote:
On February 24, 2016 10:22:03 PM EST, Phil Bouchard
wrote: 2) I would pass the pointer parameters as references
That would be a pessimization for the 99% case, I would imagine.
I'm pretty sure these references will help out optimization of the raw pointer parameters as well. Anyway I'm very close to get my pointer work correctly now with or without this optimization... But if people want real memory managment then they will use references in the container API.
On February 26, 2016 12:49:19 AM EST, Phil Bouchard
On 2016-02-25 8:38 PM, Rob Stewart wrote:
On February 24, 2016 10:22:03 PM EST, Phil Bouchard
wrote: 2) I would pass the pointer parameters as references
That would be a pessimization for the 99% case, I would imagine.
I'm pretty sure these references will help out optimization of the raw pointer parameters as well.
Since references are implemented as pointers, how would pointer to pointer arguments help anything? ___ Rob (Sent from my portable computation engine)
On 2016-02-26 4:23 AM, Rob Stewart wrote:
On February 26, 2016 12:49:19 AM EST, Phil Bouchard
wrote: On 2016-02-25 8:38 PM, Rob Stewart wrote:
On February 24, 2016 10:22:03 PM EST, Phil Bouchard
wrote: 2) I would pass the pointer parameters as references
That would be a pessimization for the 99% case, I would imagine.
I'm pretty sure these references will help out optimization of the raw pointer parameters as well.
Since references are implemented as pointers, how would pointer to pointer arguments help anything?
1) Let's assume we have this program: #include <iostream> using namespace std; inline void foo1(int * p) { *p = -1; } inline void foo2(int * p) { foo1(p); } inline void foo3(int * p) { foo2(p); } inline void bar1(int * & p) { *p = -2; } inline void bar2(int * & p) { bar1(p); } inline void bar3(int * & p) { bar2(p); } void __attribute__ ((noinline)) foo(int * p) // by value { foo3(p); } void __attribute__ ((noinline)) bar(int * & p) // by reference { bar3(p); } int main() { int * p = new int; cout << __FUNCTION__ << ": " << *p << std::endl; foo(p); cout << __FUNCTION__ << ": " << *p << std::endl; bar(p); cout << __FUNCTION__ << ": " << *p << std::endl; } 2) It outputs the following: main: 0 main: -1 main: -2 3) And when I look at the dissasembly: 00000001004010d0 <_Z3fooPi>: 1004010d0: c7 01 ff ff ff ff movl $0xffffffff,(%rcx) 1004010d6: c3 retq 00000001004010e0 <_Z3barRPi>: 1004010e0: 48 8b 01 mov (%rcx),%rax 1004010e3: c7 00 fe ff ff ff movl $0xfffffffe,(%rax) 1004010e9: c3 retq I conclude that there is not much difference between foo() and bar(). But in the case of passing by value, these pointer are just filling up the registers. But what happens when you have more pointers than registers available? The ending assembly will be worse it this case for sure. -Phil
On 2016-02-26 12:49 AM, Phil Bouchard wrote:
Anyway I'm very close to get my pointer work correctly now with or without this optimization...
It looks like this function is the source of all evil: template < typename NodeTraits > struct default_header_holder : public NodeTraits::node { typedef NodeTraits node_traits; typedef typename node_traits::node node; typedef typename node_traits::node_ptr node_ptr; typedef typename node_traits::const_node_ptr const_node_ptr; node_ptr get_node() { return pointer_traits< node_ptr >::pointer_to(*static_cast< node*
(this)); }
[...] ...
On 2016-02-26 12:49 AM, Phil Bouchard wrote:
Anyway I'm very close to get my pointer work correctly now with or without this optimization...
Good news... I'm able to make the pointer run correctly using MSVC's STL (minus one strange use case)! Although the code isn't optimized at all it works correctly. I will try to optimize the code before submitting it.
participants (4)
-
Ion Gaztañaga
-
Phil Bouchard
-
Rob Stewart
-
Steven Watanabe