So I renamed block_ptr<> to root_ptr<> and the code is accessible from here: https://github.com/philippeb8/root_ptr I am sorry but I made a mistake in the benchmark again. root_ptr<> wasn't using the fast allocator. Now it does and the new benchmark is: unique_ptr (new): 42.3736 unique_ptr (make_unique): 59.6104 shared_ptr (new): 69.9175 shared_ptr (make_shared): 46.9994 shared_ptr (allocate_shared_noinit): 31.0648 root_ptr (new): 30.5549 Regards, -Phil
On 03/13/2016 08:11 PM, Phil Bouchard wrote:
So I renamed block_ptr<> to root_ptr<> and the code is accessible from here: https://github.com/philippeb8/root_ptr
I am sorry but I made a mistake in the benchmark again. root_ptr<> wasn't using the fast allocator. Now it does and the new benchmark is:
unique_ptr (new): 42.3736 unique_ptr (make_unique): 59.6104 shared_ptr (new): 69.9175 shared_ptr (make_shared): 46.9994 shared_ptr (allocate_shared_noinit): 31.0648 root_ptr (new): 30.5549
I just re-added the unification of proxies so now root_ptr<>s can be unified: https://github.com/philippeb8/root_ptr/blob/master/example/root_ptr_test1.cp... It is pretty much bullet-proof now functionality wise. But I still need to clean up the code. Now I have a question: in my code I use a series of const_casts and mutable qualifiers. Does that automatically removes its eligibility for eventual inclusion into Boost? https://github.com/philippeb8/root_ptr/blob/master/include/boost/smart_ptr/r... Regards, -Phil
Phil Bouchard wrote:
An easy way to use a custom allocator is by deriving from block<>:
template <typename T> struct userblock : public block
{ }; And then you can instantiate using:
proxy_ptr<int> x(new userblock<int>());
Phil, how would you do the following, with your block pointer:
small_object_allocator_state a1(buffer1, size1);
small_object_allocator_state a2(buffer2, size2);
std::vector
Edit: Corrected "s1" and "s2" to "a1" and "a2" in the example code: Phil Bouchard wrote:
An easy way to use a custom allocator is by deriving from block<>:
template <typename T> struct userblock : public block
{ }; And then you can instantiate using:
proxy_ptr<int> x(new userblock<int>());
Phil, how would you do the following, with your block pointer:
small_object_allocator_state a1(buffer1, size1);
small_object_allocator_state a2(buffer2, size2);
std::vector
On 03/14/2016 08:17 AM, Glen Fernandes wrote:
If I want to use block_ptr in that style above, with a "small_object_allocator" instance constructed from a "small_object_allocator_state" like "a1", _without_ having to write any additional classes, what would the line look like?
proxy_ptr<int> p3(new block
(/* some place to specify 'a1' here? */));
Indeed, I need to add a way to pass a1 in the constructor.
And then are you guaranteeing that 'new' expression in that construction of proxy_ptr will also use a 'small_object_allocator{a1}' allocator instance for dynamic allocation, and not '::operator new(std:;size_t)'?
Yes because I use:
node
On Mar 14, 2016; 8:06am, Phil Bouchard wrote:
Indeed, I need to add a way to pass a1 in the constructor.
Yes, but in addition to that, the concern is:
Yes because I use: node
>::operator new ()
Given:
new block
I created an example test case for you: https://github.com/philippeb8/root_ptr/issues/1 You should only have to modify lines [45, 48]. i.e. Changing "shared_ptr" to "root_ptr" and changing "allocate_shared" to your mechanism of constructing your root pointer. If it throws an exception upon running, then your root pointer does not support the allocator model. The example program I wrote there should run without throwing an exception: g++ -std=c++14 -o example example.cpp && ./example Glen -- View this message in context: http://boost.2283326.n4.nabble.com/Root-Pointer-Benchmark-tp4684533p4684566.... Sent from the Boost - Dev mailing list archive at Nabble.com.
On 03/14/2016 12:53 PM, Glen Fernandes wrote:
I created an example test case for you: https://github.com/philippeb8/root_ptr/issues/1
You should only have to modify lines [45, 48].
i.e. Changing "shared_ptr" to "root_ptr" and changing "allocate_shared" to your mechanism of constructing your root pointer.
If it throws an exception upon running, then your root pointer does not support the allocator model.
The example program I wrote there should run without throwing an exception:
g++ -std=c++14 -o example example.cpp && ./example
This won't compile out of the box because I need to comment: - node<>::static_pool() - node<>::operator new - node<>::operator delete But if you comment out the aforementioned functions then the following will work without throwing anything: https://github.com/philippeb8/root_ptr/blob/master/example/allocator.cpp I could add wrappers, etc. but it works this way. It looks like I need to cleanup that node_base.hpp header as well. Thanks, -Phil
On Mon, Mar 14, 2016 at 7:13 PM, Phil Bouchard
On 03/14/2016 12:53 PM, Glen Fernandes wrote:
You should only have to modify lines [45, 48].
i.e. Changing "shared_ptr" to "root_ptr" and changing "allocate_shared" to your mechanism of constructing your root pointer.
This won't compile out of the box because I need to comment: - node<>::static_pool() - node<>::operator new - node<>::operator delete
But if you comment out the aforementioned functions then the following will work without throwing anything: https://github.com/philippeb8/root_ptr/blob/master/example/allocator.cpp
Comment out what from where? More simply, if someone wants to use
root_ptr with a conforming C++ allocator (such as Allocator<T> in that
example) what must they do?
e.g. With shared_ptr they would use allocate_shared:
shared_ptr<int> p1 = allocate_shared<int>(Allocator<int>(state));
e.g. With vector they would just use the constructor:
vector
From the code that you showed, it looks like for block_ptr, they would need to do: nodealloc<int>::PoolType a1(state); root_ptr<int> p1 = new(a1) nodealloc<int>(a1);
But first they need to define the nodealloc class template?! That doesn't seem right. What happens if they want to pass constructor parameters as well? struct T { T(int, char, bool) { } }; auto p1 = std::allocate_shared<T>(Allocator<T>(state), 5, 'g', false); How would they do that with root_ptr? Would they have to define a new nodealloc class template to do it? Glen
On 03/14/2016 08:12 PM, Glen Fernandes wrote:
Comment out what from where? More simply, if someone wants to use root_ptr with a conforming C++ allocator (such as Allocator<T> in that example) what must they do?
e.g. With shared_ptr they would use allocate_shared: shared_ptr<int> p1 = allocate_shared<int>(Allocator<int>(state));
e.g. With vector they would just use the constructor: vector
v1(Allocator<int>(state)); e.g. With function they would just use the constructor: function
f1(allocator_arg, Allocator<void>(state)); From the code that you showed, it looks like for block_ptr, they would need to do: nodealloc<int>::PoolType a1(state); root_ptr<int> p1 = new(a1) nodealloc<int>(a1);
But first they need to define the nodealloc class template?! That doesn't seem right.
No I just scribbled something quickly but I need to clean up node_base.hpp and make nodealloc<> generic.
What happens if they want to pass constructor parameters as well?
struct T { T(int, char, bool) { } }; auto p1 = std::allocate_shared<T>(Allocator<T>(state), 5, 'g', false);
How would they do that with root_ptr? Would they have to define a new nodealloc class template to do it?
No like I was saying nodealloc<> could be used for other instantiated allocators as well. And I could well easily define function wrappers as well to something like "std::allocate_node<>" but ideally I would prefer not to because I find it redundant if the placement operator new works correctly.
On Mon, Mar 14, 2016 at 8:43 PM, Phil Bouchard wrote:
No I just scribbled something quickly but I need to clean up node_base.hpp and make nodealloc<> generic.
Understood. Given that: I've updated the example code to be slightly less trivial: https://github.com/philippeb8/root_ptr/issues/1 After you have updated/cleaned up the code as you've specified, the only changes involved should be: 1. shared_ptr<U> becomes root_ptr<U> 2. allocate_shared<U>(Allocator<U>(x, y), p, q) becomes <something> That <something> should ideally be a single expression where you can specify both: a. Allocator<U> instance b. U constructor arguments Glen
On 03/14/2016 08:57 PM, Glen Fernandes wrote:
On Mon, Mar 14, 2016 at 8:43 PM, Phil Bouchard wrote:
No I just scribbled something quickly but I need to clean up node_base.hpp and make nodealloc<> generic.
Understood. Given that: I've updated the example code to be slightly less trivial:
https://github.com/philippeb8/root_ptr/issues/1
After you have updated/cleaned up the code as you've specified, the only changes involved should be:
1. shared_ptr<U> becomes root_ptr<U> 2. allocate_shared<U>(Allocator<U>(x, y), p, q) becomes <something>
That <something> should ideally be a single expression where you can specify both:
a. Allocator<U> instance b. U constructor arguments
Ok I'll do that tomorrow evening.
On 03/14/2016 08:57 PM, Glen Fernandes wrote:
On Mon, Mar 14, 2016 at 8:43 PM, Phil Bouchard wrote:
No I just scribbled something quickly but I need to clean up node_base.hpp and make nodealloc<> generic.
Understood. Given that: I've updated the example code to be slightly less trivial:
https://github.com/philippeb8/root_ptr/issues/1
After you have updated/cleaned up the code as you've specified, the only changes involved should be:
1. shared_ptr<U> becomes root_ptr<U> 2. allocate_shared<U>(Allocator<U>(x, y), p, q) becomes <something>
That <something> should ideally be a single expression where you can specify both:
a. Allocator<U> instance b. U constructor arguments
Ok I fixed it and the code will look like the following: int main() { int n1 = 0, m1 = 0; int n2 = 0, m2 = 0; { typedef boost::node node; typedef typename node::allocator_type allocator_type; boost::root_ptr<U> p1, p2, p3; allocator_type a1(n1, m1); p1 = new (a1) node(a1, 1, 'a'); allocator_type a2(n2, m2); p2 = new (a2) node(a2, 2, 'b'); allocator_type a3(n2, m2); p3 = new (a3) node(a3, 3, 'c'); if (n1 != 1 || m1 != 1 || n2 != 2 || m2 != 2) { throw 3; } } if (n1 != 0 || m1 != 0 || n2 != 0 || m2 != 0) { throw 4; } } Or: https://github.com/philippeb8/root_ptr/blob/master/example/allocator.cpp But I found a problem with pool_allocator::construct() because it is not a template function. Thus this prevents other examples to compile. Thanks, -Phil
On Tue, Mar 15, 2016 at 7:02 PM, Phil Bouchard wrote:
Ok I fixed it and the code will look like the following:
[snip]
{ typedef boost::node node; typedef typename node::allocator_type allocator_type;
boost::root_ptr<U> p1, p2, p3;
allocator_type a1(n1, m1); p1 = new (a1) node(a1, 1, 'a');
Hi Phil, I'll be able to check it out and reply further once I get home, but while I'm still in transit: The first thing that stands out as concerning is: Compared to a very simple: p = allocate_shared<T>(instance, args...); Your pointer type requires: boost::node::allocator_type a(instance); p = new (a) boost::node(a, args...); Before we even get into potentially undesirable implementation mechanics of 'node' there, the above is clearly not intuitive or clean. i.e. Why can't it even be written as a single: p = [expression involving 'a', and 'args...']; You mentioned a while back that you preferred: p.reset(new X(args...)); because it was intuitive, and in your opinion more intuitive than: p = f<X>(args...); Nobody would have any issue with that. But people would certainly have issue with: Y::Z b(a); p = new (b) Q(b, args...); compared to p = g<X>(a, args...); Glen Glen
On 03/15/2016 07:25 PM, Glen Fernandes wrote:
You mentioned a while back that you preferred: p.reset(new X(args...)); because it was intuitive, and in your opinion more intuitive than: p = f<X>(args...);
Nobody would have any issue with that. But people would certainly have issue with: Y::Z b(a); p = new (b) Q(b, args...); compared to p = g<X>(a, args...);
Well first if you have a as an r-value:
p = g<X>(a, args...)
That means the allocator parameter must be constant:
g<X>(Allocator const &, arg...)
If it's constant it won't be able to change its internal state. I
thought that was the purpose of having instantiable allocators?
I can write a wrapper function for:
p1 = new (a1) node(a1, 1, 'a');
But not for the declaration of the allocator:
boost::node::allocator_type a1(n1, m1);
Why? Because you allocate node<U>s, not Us. I could write some
node_traits<> helper:
template
On Tue, Mar 15, 2016 at 8:31 PM, Phil Bouchard wrote:
Well first if you have a as an r-value: p = g<X>(a, args...)
That means the allocator parameter must be constant: g<X>(Allocator const &, arg...)
If it's constant it won't be able to change its internal state. I thought that was the purpose of having instantiable allocators?
I think you do not understand the allocator model. 'const A&' is fine
for the allocator argument.
std::vector
On 03/15/2016 08:40 PM, Glen Fernandes wrote:
I think you do not understand the allocator model. 'const A&' is fine for the allocator argument.
Yes you're right. I need to make my references const.
std::vector
's constructors have a 'const A&' parameter. std::allocate_shared takes a 'const A&' parameter. std::function's function<A> constructor takes a 'const A&' parameter. All of the above copy-initialize an A instance from the given parameter, and would thus have a non-const A instance on which to call allocate(), et cetera.
The way that the stateful allocators would be designed is such that they all reference the same shared state (similar to 'Allocator' in that example.cpp I gave you).
Thanks for the clarifications.
On Tue, Mar 15, 2016 at 8:58 PM, Phil Bouchard
Yes you're right. I need to make my references const.
[snip]
Thanks for the clarifications.
No problem. Remember the goal isn't to provide convoluted interfaces
that are strange to people who are used to a simpler convention
established in the C++ standard library (or Boost, or any other
library that supports C++ allocator concepts).
The Allocator class template in the example you have is a valid C++
stateful allocator. Observe how it is used with existing C++ standard
library facilities that are allocator aware:
int c1 = 0, c2 = 0;
vector
On 03/15/2016 09:07 PM, Glen Fernandes wrote:
On Tue, Mar 15, 2016 at 8:58 PM, Phil Bouchard
wrote: Yes you're right. I need to make my references const.
[snip]
Thanks for the clarifications.
No problem. Remember the goal isn't to provide convoluted interfaces that are strange to people who are used to a simpler convention established in the C++ standard library (or Boost, or any other library that supports C++ allocator concepts).
The Allocator class template in the example you have is a valid C++ stateful allocator. Observe how it is used with existing C++ standard library facilities that are allocator aware:
int c1 = 0, c2 = 0;
vector
v(Allocator<char>(c1, c2)); list
l(Allocator<int>(c1, c2)); function
f(allocator_arg, Allocator<void>(c1, c2), [](int){ }); auto p = allocate_shared<double>(Allocator<double>(c1, c2), 1.5);
With your root_ptr, the interface for creation should be equally simple. No temporaries required. No extremely long type definitions required. And certainly no expressions that look like: new (temporary) Type(temporary, ...) (i.e. an expression that looks like 'temporary' is both the subject of the placement-new and an argument to the constructor of Type).
I'm still working on it but right now I have already simplified the syntax, by adding a wrapper function, to: int main() { int n1 = 0, m1 = 0; int n2 = 0, m2 = 0; { typedef boost::node node; boost::root_ptr<U> p1, p2, p3; node::allocator_type a1(n1, m1); node::allocator_type a2(n2, m2); node::allocator_type a3(n2, m2); p1 = node::allocate(a1, 1, 'a'); p2 = node::allocate(a2, 2, 'b'); p3 = node::allocate(a3, 3, 'c'); if (n1 != 1 || m1 != 1 || n2 != 2 || m2 != 2) { throw 3; } } if (n1 != 0 || m1 != 0 || n2 != 0 || m2 != 0) { throw 4; } } -Phil
On 03/15/2016 09:57 PM, Phil Bouchard wrote:
I'm still working on it but right now I have already simplified the syntax, by adding a wrapper function, to:
int main() { int n1 = 0, m1 = 0; int n2 = 0, m2 = 0; { typedef boost::node node;
boost::root_ptr<U> p1, p2, p3;
node::allocator_type a1(n1, m1); node::allocator_type a2(n2, m2); node::allocator_type a3(n2, m2);
p1 = node::allocate(a1, 1, 'a'); p2 = node::allocate(a2, 2, 'b'); p3 = node::allocate(a3, 3, 'c');
if (n1 != 1 || m1 != 1 || n2 != 2 || m2 != 2) { throw 3; } } if (n1 != 0 || m1 != 0 || n2 != 0 || m2 != 0) { throw 4; } }
Ok sorry for the delay but it's fixed now: int main() { int n1 = 0, m1 = 0; int n2 = 0, m2 = 0; { typedef boost::node node; boost::root_ptr<U> p1; boost::root_ptr<U> p2; boost::root_ptr<U> p3; p1 = node::allocate(node::allocator_type(n1, m1), 1, 'a'); p2 = node::allocate(node::allocator_type(n2, m2), 2, 'b'); p3 = node::allocate(node::allocator_type(n2, m2), 3, 'c'); if (n1 != 1 || m1 != 1 || n2 != 2 || m2 != 2) { throw 3; } } if (n1 != 0 || m1 != 0 || n2 != 0 || m2 != 0) { throw 4; } }
On Tue, Mar 15, 2016 at 10:50 PM, Phil Bouchard wrote:
Ok sorry for the delay but it's fixed now:
[snip]
typedef boost::node node;
boost::root_ptr<U> p1;
p1 = node::allocate(node::allocator_type(n1, m1), 1, 'a');
1. Your other examples won't compile (e.g. your benchmark.cpp), as you
have found out, with these changes, for the obvious reason(s) - e.g.
requiring allocator to provide construct/destroy (which a conforming
allocator does not have to do in C++11 and above).
2. You should be rebinding to value_type to construct() the value type
object (in the same way to you rebind to node type to allocate() node
type object). Likewise for destroy().
3. Surely:
p1 = node::allocate(node
::allocator_type(x, y), p, q)
can become simpler still. i.e. the target is still something as clean as: p1 = allocate_shared<U>(Allocator(x, y), p, q); 4. No 'const_cast'-ing away 'const'. You need to use the allocators correctly. Glen
On 03/15/2016 11:29 PM, Glen Fernandes wrote:
1. Your other examples won't compile (e.g. your benchmark.cpp), as you have found out, with these changes, for the obvious reason(s) - e.g. requiring allocator to provide construct/destroy (which a conforming allocator does not have to do in C++11 and above).
I need to see how the containers handle it again.
2. You should be rebinding to value_type to construct() the value type object (in the same way to you rebind to node type to allocate() node type object). Likewise for destroy().
I am not sure I understand this statement correctly.
3. Surely:
p1 = node::allocate(node
::allocator_type(x, y), p, q)
can become simpler still. i.e. the target is still something as clean as:
p1 = allocate_shared<U>(Allocator(x, y), p, q);
4. No 'const_cast'-ing away 'const'. You need to use the allocators correctly.
;) Those are just temporary. I call it a night.
On 03/15/2016 11:29 PM, Glen Fernandes wrote:
3. Surely:
p1 = node::allocate(node
::allocator_type(x, y), p, q)
can become simpler still. i.e. the target is still something as clean as:
p1 = allocate_shared<U>(Allocator(x, y), p, q);
I have simplified it and now it cannot be any simpler than the following
(using template template argument):
template
4. No 'const_cast'-ing away 'const'. You need to use the allocators correctly.
I took the const_cast<>s away.
On 03/16/2016 05:35 PM, Phil Bouchard wrote:
I have simplified it and now it cannot be any simpler than the following (using template template argument):
template
class Allocator { [...] int main() { int n1 = 0, m1 = 0; int n2 = 0, m2 = 0; { boost::root_ptr<U> p1, p2, p3; p1 = boost::allocate_node<U>(boost::make_node_allocator
(n1, m1), 1, 'a'); p2 = boost::allocate_node<U>(boost::make_node_allocator (n2, m2), 2, 'b'); p3 = boost::allocate_node<U>(boost::make_node_allocator (n2, m2), 3, 'c'); if (n1 != 1 || m1 != 1 || n2 != 2 || m2 != 2) { throw 3; } } if (n1 != 0 || m1 != 0 || n2 != 0 || m2 != 0) { throw 4; } }
Or: https://github.com/philippeb8/root_ptr/blob/master/example/allocator.cpp#L82
Is that acceptable? I am working on the neural network right now so I can give it the ultimate test.
On 03/17/2016 06:58 PM, Glen Fernandes wrote:
On Thu, Mar 17, 2016 at 6:49 PM, Phil Bouchard
wrote: Is that acceptable?
Looks much better.
I'm assuming allocate_node<U>(Allocator<U>(n1, m1), 1, 'a'); would also work, in which case the interface is as tidy as allocate_shared.
No I'm sorry but:
allocate_node<U>(Allocator<U>(n1, m1), 1, 'a');
Can't work. It needs to be in the form:
allocate_node<U>(make_node_allocator
On 03/15/2016 11:29 PM, Glen Fernandes wrote:
1. Your other examples won't compile (e.g. your benchmark.cpp), as you have found out, with these changes, for the obvious reason(s) - e.g. requiring allocator to provide construct/destroy (which a conforming allocator does not have to do in C++11 and above).
Fixed. I am now using the container allocator traits' constructor / destructor.
On 03/15/2016 11:29 PM, Glen Fernandes wrote:
1. Your other examples won't compile (e.g. your benchmark.cpp), as you have found out, with these changes, for the obvious reason(s) - e.g. requiring allocator to provide construct/destroy (which a conforming allocator does not have to do in C++11 and above).
All the examples work fine now.
On 16/03/2016 13:31, Phil Bouchard wrote:
On 03/15/2016 07:25 PM, Glen Fernandes wrote:
You mentioned a while back that you preferred: p.reset(new X(args...)); because it was intuitive, and in your opinion more intuitive than: p = f<X>(args...);
Nobody would have any issue with that. But people would certainly have issue with: Y::Z b(a); p = new (b) Q(b, args...); compared to p = g<X>(a, args...);
Well first if you have a as an r-value: p = g<X>(a, args...)
That's an lvalue, not an rvalue.
That means the allocator parameter must be constant: g<X>(Allocator const &, arg...)
If it's constant it won't be able to change its internal state. I thought that was the purpose of having instantiable allocators?
There's no need for (and no reason for) the allocator to be a const reference.
I can write a wrapper function for: p1 = new (a1) node(a1, 1, 'a');
But not for the declaration of the allocator: boost::node::allocator_type a1(n1, m1);
Why? Because you allocate node<U>s, not Us. I could write some node_traits<> helper:
template
{ typedef typename boost::node ::allocator_type allocator_type; }; So that the declaration becomes: boost::node_traits::allocator_type a1(n1, m1);
But that's all I can do.
Admittedly I'm not familiar with the changes to allocators in C++11 yet, but C++03 allocators support accepting an allocator (even a stateful one) of one type and then using it to make allocations of a different type, via rebind and a templated constructor. std::list and friends use that functionality extensively.
On 03/15/2016 08:42 PM, Gavin Lambert wrote:
Admittedly I'm not familiar with the changes to allocators in C++11 yet, but C++03 allocators support accepting an allocator (even a stateful one) of one type and then using it to make allocations of a different type, via rebind and a templated constructor. std::list and friends use that functionality extensively.
Yes I'm using rebinds extensively: https://github.com/philippeb8/root_ptr/blob/master/include/boost/smart_ptr/d...
On Tue, Mar 15, 2016 at 7:02 PM, Phil Bouchard wrote:
Ok I fixed it and the code will look like the following:
One more thing: I suspect the following will not work, with a glance at your code: Change 'U' into: struct W { explicit W(int) { } W(const W&) = delete; W(W&&) { } W& operator=(const W&) = delete; W& operator=(W&&) = delete; }; struct U { U(W&&) { } }; Now with shared_ptr and allocate_shared, this will compile just fine: p1 = allocate_shared<U>(Allocator<U>(n1, m2), W(1)); With root_ptr, I'm guessing you would change it to something like: allocator_type a1(n1, m1); p1 = new (a1) node(a1, W(1)); Your implementation looks like it will try to copy W which would fail to compile. Glen
On 03/15/2016 08:33 PM, Glen Fernandes wrote:
On Tue, Mar 15, 2016 at 7:02 PM, Phil Bouchard wrote:
Ok I fixed it and the code will look like the following:
One more thing: I suspect the following will not work, with a glance at your code: Change 'U' into:
struct W { explicit W(int) { } W(const W&) = delete; W(W&&) { } W& operator=(const W&) = delete; W& operator=(W&&) = delete; }; struct U { U(W&&) { } };
Now with shared_ptr and allocate_shared, this will compile just fine:
p1 = allocate_shared<U>(Allocator<U>(n1, m2), W(1));
With root_ptr, I'm guessing you would change it to something like:
allocator_type a1(n1, m1); p1 = new (a1) node(a1, W(1));
Your implementation looks like it will try to copy W which would fail to compile.
It fails to compile (I do not support move semantics yet): allocator.cpp:65:9: error: no matching function for call to ‘U::U(const W&)’ ::new(p) U(std::forward<Args>(args)...);
AMDG On 03/14/2016 06:43 PM, Phil Bouchard wrote:
On 03/14/2016 08:12 PM, Glen Fernandes wrote:
How would they do that with root_ptr? Would they have to define a new nodealloc class template to do it?
No like I was saying nodealloc<> could be used for other instantiated allocators as well.
I'm not really following this thread, but I just want to point out that nodealloc is a terrible name because it can be read as either "no dealloc" or "node alloc." In Christ, Steven Watanabe
On Mon, Mar 14, 2016 at 9:19 PM, Steven Watanabe wrote:
I'm not really following this thread, but I just want to point out that nodealloc is a terrible name because it can be read as either "no dealloc" or "node alloc."
+1. But the whole 'new (x) T(x)' thing is a much bigger problem than his choice of name for 'T'. Glen
On 03/14/2016 09:30 PM, Glen Fernandes wrote:
On Mon, Mar 14, 2016 at 9:19 PM, Steven Watanabe wrote:
I'm not really following this thread, but I just want to point out that nodealloc is a terrible name because it can be read as either "no dealloc" or "node alloc."
+1.
But the whole 'new (x) T(x)' thing is a much bigger problem than his choice of name for 'T'.
They commonly use placement operator new in WebKit...
On March 14, 2016 7:21:40 AM EDT, Phil Bouchard
I just re-added the unification of proxies so now root_ptr<>s can be unified:
https://github.com/philippeb8/root_ptr/blob/master/example/root_ptr_test1.cp...
It is pretty much bullet-proof now functionality wise. But I still need to clean up the code.
I really wonder about that claim. You seem to keep changing design aspects, adding and removing things, so I wonder how comprehensive your tests are. (I realize that you may be adding more test cases in response to queries on this list, but the instability is worrisome.)
Now I have a question: in my code I use a series of const_casts and mutable qualifiers. Does that automatically removes its eligibility for eventual inclusion into Boost?
https://github.com/philippeb8/root_ptr/blob/master/include/boost/smart_ptr/r...
I can't tell which is line 67 via my phone, but taking an argument by reference to const and then casting away constness is always cause for concern. ___ Rob (Sent from my portable computation engine)
On 03/14/2016 11:27 AM, Rob Stewart wrote:
On March 14, 2016 7:21:40 AM EDT, Phil Bouchard
wrote: I just re-added the unification of proxies so now root_ptr<>s can be unified:
https://github.com/philippeb8/root_ptr/blob/master/example/root_ptr_test1.cp...
It is pretty much bullet-proof now functionality wise. But I still need to clean up the code.
I really wonder about that claim. You seem to keep changing design aspects, adding and removing things, so I wonder how comprehensive your tests are. (I realize that you may be adding more test cases in response to queries on this list, but the instability is worrisome.)
I was gravitating around a central goal for a while but the design is really solid right now.
Now I have a question: in my code I use a series of const_casts and mutable qualifiers. Does that automatically removes its eligibility for eventual inclusion into Boost?
https://github.com/philippeb8/root_ptr/blob/master/include/boost/smart_ptr/r...
I can't tell which is line 67 via my phone, but taking an argument by reference to const and then casting away constness is always cause for concern.
I can take away the const_casts because it's just an internal shortcut I used but mutable members will stay mutable because it's not modifying the objects externally and won't break constant parameters. It is used internally only, just like caching.
participants (5)
-
Gavin Lambert
-
Glen Fernandes
-
Phil Bouchard
-
Rob Stewart
-
Steven Watanabe