string/vector extensions for C interop

147 views
Skip to first unread message

gmis...@gmail.com

unread,
Jan 9, 2017, 7:48:48 PM1/9/17
to ISO C++ Standard - Future Proposals
string/vector extensions for C interop

I've started this thread so the original thread it came doesn't continue to get re-directed.
I've taken some comments from that to restart the discussion and re-worked my example a bit. So:

We seem to have a situation where C is in free-fall decline (at least on the tiobe index).

But if we can do more to support C programmers moving over to C++ it would be a win for both camps.

C++ users could use certain performance tuning in this area regardless because we use C.

To quote r very own mr smith:

"The fact that you can't resize a string or vector without initializing its elements is a measurable and significant performance problem for some applications; I have seen people invent their own string type or do truly horrible things to std::string (directly poking at its internals) to circumvent that."


So what can we do to stop this?


I have seen a lot of code like this that I'd like to not write/fix/use:


char* do_something_for_c_library()
{
 std::string s;
 s.resize(n+1); // We don't want zero fill here.
// SomeCAPI takes a pointer an a length and returns the actual length it filled.
 auto len = SomeCAPI(s.data(), n); /* Win32 I'm looking at you. */
 s.resize(len)

 s += "hello";

 char* ptr = malloc(s.length()+1);
 if (!ptr)
  return nullptr;

 strcpy(ptr, s.data());

 return ptr;
}


There are various reasons people use string like this (but vector also). These are:
1. They just intend to return a string eventually but need data from a C like API. Fill can be expensive.
2. They need some RAII thing so if there's an exception the destructor will release the memory.
3. They could use unique_ptr but they want to do some string'y things first.
4. They want string for the small buffer optimization.
5. They sometimes need to return the buffer to C.


It doesn't seem like a big deal, but this is often in performance critical code. The sizes aren't always trivial.
So why can't we make this easier and more efficient?


To get this discussion started, how about:

char* do_something_for_c_library()
{
 std::string s;

 auto len = SomeCAPI(s.uinitialized_data_at(0, n+1), n);
 s.resize(len);

 s+="hello";
 return s.detach_and_string_terminate(); // And provide basic detach also.
}

s.uinitialized_data_at does this:
Ensures that a range of elements starting at 0 for length n exists.
and if it doesn't it extends it without initialization.
The starting position should exist or it's an error unless it is 0 and the string is empty.
if it can't allocate or the offset or length is bad the it throws a std::logic_error(); explaining the problem.


I don't see why we can't provide this same API for vector.
detach_and_string_terminate() could just be enable_if'd only types of char/wchar_t/unsigned char/char32_t/char16_t.


unintialized_data_at() could just be enabled for these types too for now if that helps safety.

I think this would:
1. Increase performance as it enables a lot less pointless initializing of data that will only be overwritten.
2. Increase performance because it enables a lot of less excess allocations in many cases.
3. Reduce code size because the library is doing the work.
4. Improve safety because the library is doing the safety checking for the main fail points that users often don't check.
It has to do some checking anyway because it may be re-allocating.
5. Help C programmers and C++ programmers who have to use or enable C api's.

We could provide data_at() too. These can be free functions perhaps.
I would like an API to request allocation of an exact buffer size too but that doesn't have to be these API's.

The detach api proposal can be separate from the data_at idea.
I don't think this idea needs to wait for some perfect language extensions.

Questions:
Why not basically this?
Do we really need to wait 3 years for ALL of this?
But is providing the minimum to support a minimum of the uninitialized_data_at routine so hard that we need to wait?
If there's something better. What is it?

Thanks

Nicol Bolas

unread,
Jan 9, 2017, 8:35:54 PM1/9/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com

Several reasons.

First, `basic_string` is intended to be able to have small string optimization (SSO). This means that strings below a certain size are stored internally rather than allocating memory. Thus, your "detach" function doesn't "detach" something in all cases.

Second, `basic_string` and `vector` both allocate memory based on provided allocators. So... how will the user destroy it? They cannot call `delete[]` on it, since it was not allocated with `new[]`. The only way to destroy this object us to use the same allocator that was used to allocate it, or a compatible one. Not only that, the person receiving the pointer has no idea how many objects are in the array, so unless `T` has a trivial destructor, you need to know how many items to destroy. And you need to remember to destroy them in reverse order.

Third, your APIs are really bad. Inserting default-initialized objects shouldn't use radically different APIs from inserting value-initialized objects. Your API also assumes that `T` is a type which can tolerate being uninitialized. We shouldn't make APIs that break the C++ object model; we should make them that actually work with that model.

The goal is this:

T *t = new T[256];
vector
<T> tv(256, ...);

Both of these arrays should perform the same amount of initializing of their respective arrays. If `T` is trivially default constructible, then both of these will be uninitialized.  If `T` has a non-trivial default constructor, then it will be called 256 times in both cases. Because by the rules of C++, that's what `T` requires in order to be a live object.

The goal should not be to have `vector/string` emulate `malloc`/casting/etc. If you want to violate the C++ object model, that's your business, but we shouldn't have standard library types let you do that.

Do we really need to wait 3 years for ALL of this?

Yes. Be glad it's just 3 years.
 
But is providing the minimum to support a minimum of the uninitialized_data_at routine so hard that we need to wait?

You cannot get something into the standard right now just because you really want it. C++17 was feature-complete months ago. The ship has sailed; it's not coming back into port.

The next ship launches in 3 years. Get ready for it.

If there's something better. What is it?

Well, there's what I already suggested.

I also spent a little time thinking about a memory detachment API for vector, one that would actually recognize things like the fact that allocators exist ;) Since then, we've had the introduction of `map`/`set` extract/merge functions, and we see an alternate way to handle transfer of such objects.

The design of such an API should mirror them, not deal in direct pointers to something. Also, such a design should include the ability to hand the system existing memory (and an allocator for deleting it), which can then be transferred into a `vector`/`string`.

gmis...@gmail.com

unread,
Jan 9, 2017, 8:57:39 PM1/9/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com


Several reasons.

First, `basic_string` is intended to be able to have small string optimization (SSO). This means that strings below a certain size are stored internally rather than allocating memory. Thus, your "detach" function doesn't "detach" something in all cases.

That's not a reason for doing nothing. That's just a description of how things are that doesn't forward anything. I don't know why so many replies are structured like this.

Detach could allocate and copy if it must. If that fails it returns nullptr. Or uninitialized_data_at can do the allocate copy if directed, that can fail anyway so that seems the fine place to do that. We can indicate that in a parameter etc.
There are ways forward here.



Second, `basic_string` and `vector` both allocate memory based on provided allocators. So... how will the user destroy it? They cannot call `delete[]` on it, since it was not allocated with `new[]`. The only way to destroy this object us to use the same allocator that was used to allocate it, or a compatible one. Not only that, the person receiving the pointer has no idea how many objects are in the array, so unless `T` has a trivial destructor, you need to know how many items to destroy. And you need to remember to destroy them in reverse order.

Third, your APIs are really bad. Inserting default-initialized objects shouldn't use radically different APIs from inserting value-initialized objects. Your API also assumes that `T` is a type which can tolerate being uninitialized. We shouldn't make APIs that break the C++ object model; we should make them that actually work with that model.

I said we could enable_if that and that these could be free. You seem to be ignoring that fact or didn't see it. I don't see a problem with the idea.

And C++ already has plenty of 'get outs' for doing what needs to be done if it needs to be done. We should make API's that enable us to do what we need to do. You don't have to call them if you don't need what it offers. So I don't buy your argument.


The goal is this:

T *t = new T[256];
vector
<T> tv(256, ...);

Both of these arrays should perform the same amount of initializing of their respective arrays. If `T` is trivially default constructible, then both of these will be uninitialized.  If `T` has a non-trivial default constructor, then it will be called 256 times in both cases. Because by the rules of C++, that's what `T` requires in order to be a live object.

That's great but why does my suggestion break that or hinder that. So why do we have to wait for that?
Is there any guarantee we will even get that?
 

The goal should not be to have `vector/string` emulate `malloc`/casting/etc. If you want to violate the C++ object model, that's your business, but we shouldn't have standard library types let you do that.

Do we really need to wait 3 years for ALL of this?

Yes. Be glad it's just 3 years.

I can wait if I must. I was asking if I must, but if so, so be it. But I've yet to see why this is so hard.
 
 
But is providing the minimum to support a minimum of the uninitialized_data_at routine so hard that we need to wait?

You cannot get something into the standard right now just because you really want it. C++17 was feature-complete months ago. The ship has sailed; it's not coming back into port.

The next ship launches in 3 years. Get ready for it.

Well I posted this to get ready for it, if not before it. :)
 

If there's something better. What is it?

Well, there's what I already suggested.

I also spent a little time thinking about a memory detachment API for vector, one that would actually recognize things like the fact that allocators exist ;) Since then, we've had the introduction of `map`/`set` extract/merge functions, and we see an alternate way to handle transfer of such objects.

The design of such an API should mirror them, not deal in direct pointers to something. Also, such a design should include the ability to hand the system existing memory (and an allocator for deleting it), which can then be transferred into a `vector`/`string`.

I don't see how you can avoid dealing with a pointer when you (I) want to be able to return a pointer to C here.
But that doesn't preclude options for other situations.

I hope your larger proposal proceeds. I think this part of it can be worked out independent of that though at least interface wise and especially so in case the larger proposal doesn't make it through. We need something here and this is a partner or a fall back.

Thanks

Richard Smith

unread,
Jan 9, 2017, 9:03:03 PM1/9/17
to std-pr...@isocpp.org, gmis...@gmail.com
If you only provide that, you have not solved the complete problem. Sometimes the requirements do include the ability to directly construct a sequence of T objects in place within a vector, in ways that emplace does not support.

One (slightly scary) approach would be:
1) permit the user to construct objects in trailing storage of a vector/string, so long as capacity is large enough, and
2) provide a resize_already_initialized(size_t) member to resize the container so that those elements are part of its size, without constructing new Ts over the top of them

Obviously if (1) somehow fails or throws, destroying the elements it created is its problem, and triggering reallocation during (1) would be bad.

The goal should not be to have `vector/string` emulate `malloc`/casting/etc. If you want to violate the C++ object model, that's your business, but we shouldn't have standard library types let you do that.

Do we really need to wait 3 years for ALL of this?

Yes. Be glad it's just 3 years.
 
But is providing the minimum to support a minimum of the uninitialized_data_at routine so hard that we need to wait?

You cannot get something into the standard right now just because you really want it. C++17 was feature-complete months ago. The ship has sailed; it's not coming back into port.

The next ship launches in 3 years. Get ready for it.

If there's something better. What is it?

Well, there's what I already suggested.

I also spent a little time thinking about a memory detachment API for vector, one that would actually recognize things like the fact that allocators exist ;) Since then, we've had the introduction of `map`/`set` extract/merge functions, and we see an alternate way to handle transfer of such objects.

The design of such an API should mirror them, not deal in direct pointers to something. Also, such a design should include the ability to hand the system existing memory (and an allocator for deleting it), which can then be transferred into a `vector`/`string`.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/07f6e085-f75b-41f0-b42d-8a2704dbdb9a%40isocpp.org.

Nicol Bolas

unread,
Jan 9, 2017, 10:39:07 PM1/9/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
On Monday, January 9, 2017 at 9:03:03 PM UTC-5, Richard Smith wrote:
On 9 January 2017 at 17:35, Nicol Bolas <jmck...@gmail.com> wrote:
Several reasons.

First, `basic_string` is intended to be able to have small string optimization (SSO). This means that strings below a certain size are stored internally rather than allocating memory. Thus, your "detach" function doesn't "detach" something in all cases.

Second, `basic_string` and `vector` both allocate memory based on provided allocators. So... how will the user destroy it? They cannot call `delete[]` on it, since it was not allocated with `new[]`. The only way to destroy this object us to use the same allocator that was used to allocate it, or a compatible one. Not only that, the person receiving the pointer has no idea how many objects are in the array, so unless `T` has a trivial destructor, you need to know how many items to destroy. And you need to remember to destroy them in reverse order.

Third, your APIs are really bad. Inserting default-initialized objects shouldn't use radically different APIs from inserting value-initialized objects. Your API also assumes that `T` is a type which can tolerate being uninitialized. We shouldn't make APIs that break the C++ object model; we should make them that actually work with that model.

The goal is this:

T *t = new T[256];
vector
<T> tv(256, ...);

Both of these arrays should perform the same amount of initializing of their respective arrays. If `T` is trivially default constructible, then both of these will be uninitialized.  If `T` has a non-trivial default constructor, then it will be called 256 times in both cases. Because by the rules of C++, that's what `T` requires in order to be a live object.

If you only provide that, you have not solved the complete problem. Sometimes the requirements do include the ability to directly construct a sequence of T objects in place within a vector, in ways that emplace does not support.

That is a problem best solved by allowing `emplace` to construct an object in ways that it does not currently support.

What in particular was a circumstance you were thinking of?

One (slightly scary) approach would be:
1) permit the user to construct objects in trailing storage of a vector/string, so long as capacity is large enough, and
2) provide a resize_already_initialized(size_t) member to resize the container so that those elements are part of its size, without constructing new Ts over the top of them

Obviously if (1) somehow fails or throws, destroying the elements it created is its problem, and triggering reallocation during (1) would be bad.

I'm not sure why we should encourage (1) happening outside of the presence of (2). Or rather, I don't know why it is necessary to do it that way.

Can you give an example? One that is actually legal C++ under the current object model?

Nicol Bolas

unread,
Jan 9, 2017, 11:19:44 PM1/9/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
On Monday, January 9, 2017 at 8:57:39 PM UTC-5, gmis...@gmail.com wrote:


Several reasons.

First, `basic_string` is intended to be able to have small string optimization (SSO). This means that strings below a certain size are stored internally rather than allocating memory. Thus, your "detach" function doesn't "detach" something in all cases.

That's not a reason for doing nothing. That's just a description of how things are that doesn't forward anything. I don't know why so many replies are structured like this.

Detach could allocate and copy if it must. If that fails it returns nullptr. Or uninitialized_data_at can do the allocate copy if directed, that can fail anyway so that seems the fine place to do that. We can indicate that in a parameter etc.
There are ways forward here.



Second, `basic_string` and `vector` both allocate memory based on provided allocators. So... how will the user destroy it? They cannot call `delete[]` on it, since it was not allocated with `new[]`. The only way to destroy this object us to use the same allocator that was used to allocate it, or a compatible one. Not only that, the person receiving the pointer has no idea how many objects are in the array, so unless `T` has a trivial destructor, you need to know how many items to destroy. And you need to remember to destroy them in reverse order.

Third, your APIs are really bad. Inserting default-initialized objects shouldn't use radically different APIs from inserting value-initialized objects. Your API also assumes that `T` is a type which can tolerate being uninitialized. We shouldn't make APIs that break the C++ object model; we should make them that actually work with that model.

I said we could enable_if that and that these could be free. You seem to be ignoring that fact or didn't see it. I don't see a problem with the idea.

And C++ already has plenty of 'get outs' for doing what needs to be done if it needs to be done. We should make API's that enable us to do what we need to do. You don't have to call them if you don't need what it offers. So I don't buy your argument.

C++ has ways to do things that are illegal in some circumstances because those tools also permit you to do legal things that you would not otherwise be able to do. I believe that the circumstances where what you're wanting to do is actually legal C++ code can be done in ways that don't require tools that allow you to also do illegal things.

For example, a C API cannot create a non-trivial C++ object (if you want to get really technical, a C API cannot begin the lifetime of a C++ object at all, but lets pretend that trivial types can be excepted). As such, you cannot legally hand the memory of a `vector<T>` to a C API to be initialized unless `T` is trivial. Therefore, the ability to default initialize a `vector<T>` is all you need to avoid the performance penalty, since default initialization is a no-op.

Your API would look like this:

vector<T> v;
SomeCAPI(v.uinitialized_data_at(0, n), n);

My API would look like this:

vector<T> v(n, std::default_init);
SomeCAPI(v.data(), v.size());

But they would have the same performance: a single allocation of a block of `n` objects, with no initialization of that array.

So why use an API that is oddball and non-standard looking instead of an API that looks like normal `vector` mechanisms? Your way makes using "uninitialized" data look special-case, like you're cheating or something. My way makes it look normal, just like you had done `new T[n]` or whatever.

Because it is normal. You're not cheating; every step is 100% legal C++. You're not pretending that C APIs can begin the lifetime of C++ objects. You're creating an array of live C++ objects and passing them along to someone else who will trivially copy into them.

So why do we need an API that looks so alien to how the API currently works?

The goal is this:

T *t = new T[256];
vector
<T> tv(256, ...);

Both of these arrays should perform the same amount of initializing of their respective arrays. If `T` is trivially default constructible, then both of these will be uninitialized.  If `T` has a non-trivial default constructor, then it will be called 256 times in both cases. Because by the rules of C++, that's what `T` requires in order to be a live object.

That's great but why does my suggestion break that or hinder that.

Because it doesn't look like regular `vector` stuff.

So why do we have to wait for that?
Is there any guarantee we will even get that?

There's no guarantee you'll get yours either.

If there's something better. What is it?

Well, there's what I already suggested.

I also spent a little time thinking about a memory detachment API for vector, one that would actually recognize things like the fact that allocators exist ;) Since then, we've had the introduction of `map`/`set` extract/merge functions, and we see an alternate way to handle transfer of such objects.

The design of such an API should mirror them, not deal in direct pointers to something. Also, such a design should include the ability to hand the system existing memory (and an allocator for deleting it), which can then be transferred into a `vector`/`string`.

I don't see how you can avoid dealing with a pointer when you (I) want to be able to return a pointer to C here.

You can want whatever you like, but that doesn't change the fact that it's simply not possible. Why? Because you're leaking memory. Or worse, breaking the heap.

`free` cannot be called on memory allocated by `new` or `allocator::allocate` or whatever other allocator you may have used (unless that allocator explicitly uses `malloc`, of course). Therefore, the memory generated by C++ containers cannot be destroyed by C. So either C is going to try to `free` this memory and corrupt the heap, or the C API is going to call back into your code in order to free it.

It should also be noted that, at least in my experience, there aren't a lot of C APIs like this, which genuinely adopt memory allocated by external code. Lua, Cairo, etc, I can't think of one that adopts memory by return values of a callback. Generally speaking, they copy it from you.

Can you give an example where a return value from a callback is intended by a C API to be memory which is dynamically allocated in such a way that the C system can deallocate it?

Generally speaking, when transitioning from one system to another, you will need to marshal your data: to copy it from your internal data structures/memory pools into those compatible with the other system. This is inevitable and natural. And most of the C APIs I know of tend to hold to that. They'll fill in arrays of memory with data. But they almost never cross allocations like this, and for more reasons than just playing ball with C++ APIs. C programmers sometimes need to write their own heap code, and that means other systems can't deallocate memory they allocate. So in my experience, C APIs don't frequently adopt memory.

So I question the motivation for this part of your idea.

gmis...@gmail.com

unread,
Jan 10, 2017, 1:57:29 AM1/10/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com


On Tuesday, January 10, 2017 at 5:19:44 PM UTC+13, Nicol Bolas wrote:
On Monday, January 9, 2017 at 8:57:39 PM UTC-5, gmis...@gmail.com wrote:


Several reasons.

First, `basic_string` is intended to be able to have small string optimization (SSO). This means that strings below a certain size are stored internally rather than allocating memory. Thus, your "detach" function doesn't "detach" something in all cases.

That's not a reason for doing nothing. That's just a description of how things are that doesn't forward anything. I don't know why so many replies are structured like this.

Detach could allocate and copy if it must. If that fails it returns nullptr. Or uninitialized_data_at can do the allocate copy if directed, that can fail anyway so that seems the fine place to do that. We can indicate that in a parameter etc.
There are ways forward here.



Second, `basic_string` and `vector` both allocate memory based on provided allocators. So... how will the user destroy it? They cannot call `delete[]` on it, since it was not allocated with `new[]`. The only way to destroy this object us to use the same allocator that was used to allocate it, or a compatible one. Not only that, the person receiving the pointer has no idea how many objects are in the array, so unless `T` has a trivial destructor, you need to know how many items to destroy. And you need to remember to destroy them in reverse order.

Third, your APIs are really bad. Inserting default-initialized objects shouldn't use radically different APIs from inserting value-initialized objects. Your API also assumes that `T` is a type which can tolerate being uninitialized. We shouldn't make APIs that break the C++ object model; we should make them that actually work with that model.

I said we could enable_if that and that these could be free. You seem to be ignoring that fact or didn't see it. I don't see a problem with the idea.

And C++ already has plenty of 'get outs' for doing what needs to be done if it needs to be done. We should make API's that enable us to do what we need to do. You don't have to call them if you don't need what it offers. So I don't buy your argument.

C++ has ways to do things that are illegal in some circumstances because those tools also permit you to do legal things that you would not otherwise be able to do. I believe that the circumstances where what you're wanting to do is actually legal C++ code can be done in ways that don't require tools that allow you to also do illegal things.

Legal and illegal are just points in time. What is today illegal can often be made legal depending on the will and reasoning.
But something being illegal today in of itself isn't interesting.
 

For example, a C API cannot create a non-trivial C++ object (if you want to get really technical, a C API cannot begin the lifetime of a C++ object at all, but lets pretend that trivial types can be excepted). As such, you cannot legally hand the memory of a `vector<T>` to a C API to be initialized unless `T` is trivial. Therefore, the ability to default initialize a `vector<T>` is all you need to avoid the performance penalty, since default initialization is a no-op.

Your API would look like this:

vector<T> v;
SomeCAPI(v.uinitialized_data_at(0, n), n);

yes, I'm not attached to the API, but nor do I have a problem with it. I just want the ability.
 

My API would look like this:

vector<T> v(n, std::default_init);
SomeCAPI(v.data(), v.size());

But they would have the same performance: a single allocation of a block of `n` objects, with no initialization of that array.

I'm fine with your API but it's less flexible than my API unless I miss understand what yours implies.
And I feel I'm not appreciating what yours implies  Can you extend v without getting more unwanted initialization with your API?
i.e. Is v.resize(10000) going to do the right thing her and not zero fill where n in the initial call is say 1 or 0.
 

So why use an API that is oddball and non-standard looking instead of an API that looks like normal `vector` mechanisms? Your way makes using "uninitialized" data look special-case, like you're cheating or something. My way makes it look normal, just like you had done `new T[n]` or whatever.

I don't find my API that oddball but I'm not hung up on my api, I just want the feature of unintialized allocation. 


Because it is normal. You're not cheating; every step is 100% legal C++. You're not pretending that C APIs can begin the lifetime of C++ objects. You're creating an array of live C++ objects and passing them along to someone else who will trivially copy into them.

I'm not pretending that as far as I know. My API isn't asking C to begin life here. But I'm sure we'll work out whatever misunderstanding I or you have here later.
 

So why do we need an API that looks so alien to how the API currently works?
 
I don't need anything alien. I just want something that gives me unintialized allocation.
When I mooted what I need, you started talking about language changes as a requirement to progress.
I just said no, as an API should be able to suffice without a language change. Quite what the API is I'm less fussed.
We need some API with or without language change, I don't care what that is as long as it works.
I proposed *something* to get the discussion going beyond, 'oh no we can't progress until there's language change'.
 

The goal is this:

T *t = new T[256];
vector
<T> tv(256, ...);

Both of these arrays should perform the same amount of initializing of their respective arrays. If `T` is trivially default constructible, then both of these will be uninitialized.  If `T` has a non-trivial default constructor, then it will be called 256 times in both cases. Because by the rules of C++, that's what `T` requires in order to be a live object.

That's great but why does my suggestion break that or hinder that.

Because it doesn't look like regular `vector` stuff.

This isn't something I agree with. But it's not important to me. I'll ignore this for now though depending on what you reply to my other questions.
 

So why do we have to wait for that?
Is there any guarantee we will even get that?

There's no guarantee you'll get yours either.

We have more chance of getting something like mine than yours because mine doesn't require language change.
If we have to wait 3 years for either, I want the best one - but I want *something* here.
Not an attempt at yours and if it fails, nothing for 6 years. So we're having the discussion to keep all of this progressing.
 

If there's something better. What is it?

Well, there's what I already suggested.

I also spent a little time thinking about a memory detachment API for vector, one that would actually recognize things like the fact that allocators exist ;) Since then, we've had the introduction of `map`/`set` extract/merge functions, and we see an alternate way to handle transfer of such objects.

The design of such an API should mirror them, not deal in direct pointers to something. Also, such a design should include the ability to hand the system existing memory (and an allocator for deleting it), which can then be transferred into a `vector`/`string`.

I don't see how you can avoid dealing with a pointer when you (I) want to be able to return a pointer to C here.

You can want whatever you like, but that doesn't change the fact that it's simply not possible. Why? Because you're leaking memory. Or worse, breaking the heap.

`free` cannot be called on memory allocated by `new` or `allocator::allocate` or whatever other allocator you may have used (unless that allocator explicitly uses `malloc`, of course). Therefore, the memory generated by C++ containers cannot be destroyed by C. So either C is going to try to `free` this memory and corrupt the heap, or the C API is going to call back into your code in order to free it.

It should also be noted that, at least in my experience, there aren't a lot of C APIs like this, which genuinely adopt memory allocated by external code. Lua, Cairo, etc, I can't think of one that adopts memory by return values of a callback. Generally speaking, they copy it from you.

Can you give an example where a return value from a callback is intended by a C API to be memory which is dynamically allocated in such a way that the C system can deallocate it?

Generally speaking, when transitioning from one system to another, you will need to marshal your data: to copy it from your internal data structures/memory pools into those compatible with the other system. This is inevitable and natural. And most of the C APIs I know of tend to hold to that. They'll fill in arrays of memory with data. But they almost never cross allocations like this, and for more reasons than just playing ball with C++ APIs. C programmers sometimes need to write their own heap code, and that means other systems can't deallocate memory they allocate. So in my experience, C APIs don't frequently adopt memory.

This is because C and C++ don't promise to free each others memory. But this is something that could potentially be made possible and legal.
Then there would be no leak. If C and C++ are going to be the best companions possible that's something to consider making legal.
Hopefully this discussion gets people who know the area well talking about if we can and why we should do this.
But that it is illegal today in of itself means not that much.
 

So I question the motivation for this part of your idea.

You are correct, I see returning pointers to C is the least important part of my request.
It's a nice to have depending on the problems. That's why I said in my previous posts that I'm not obsessed about a detach ability for C as much as I am about the unintialized allocation ability.
It would be nice to pass data of the same type between containers for C++ but it's the uninitialized allocation I'm interested in.
Then C++ interop between containers, then C interop.

But I think if we want C code bases to come to C++ if we could make this basic interop possible it would seem to be a good thing. it just depends on what the issues are.

But for C++17, if it was just want unintialized_resize() or data_at or whatever I'd be happy. We must have this for C++20 I think, I'd ideally like this function sooner even if non standard to test with.
 

D. B.

unread,
Jan 10, 2017, 4:13:47 AM1/10/17
to std-pr...@isocpp.org
On Tue, Jan 10, 2017 at 6:57 AM, <gmis...@gmail.com> wrote:
But for C++17, if it was just want unintialized_resize() or data_at or whatever I'd be happy. We must have this for C++20 I think, I'd ideally like this function sooner even if non standard to test with.

You must have it? Then start coding it, and publish a write-up of your successful results.

Richard Smith

unread,
Jan 10, 2017, 5:00:23 AM1/10/17
to std-pr...@isocpp.org, gmis...@gmail.com
On 9 January 2017 at 19:39, Nicol Bolas <jmck...@gmail.com> wrote:
On Monday, January 9, 2017 at 9:03:03 PM UTC-5, Richard Smith wrote:
On 9 January 2017 at 17:35, Nicol Bolas <jmck...@gmail.com> wrote:
Several reasons.

First, `basic_string` is intended to be able to have small string optimization (SSO). This means that strings below a certain size are stored internally rather than allocating memory. Thus, your "detach" function doesn't "detach" something in all cases.

Second, `basic_string` and `vector` both allocate memory based on provided allocators. So... how will the user destroy it? They cannot call `delete[]` on it, since it was not allocated with `new[]`. The only way to destroy this object us to use the same allocator that was used to allocate it, or a compatible one. Not only that, the person receiving the pointer has no idea how many objects are in the array, so unless `T` has a trivial destructor, you need to know how many items to destroy. And you need to remember to destroy them in reverse order.

Third, your APIs are really bad. Inserting default-initialized objects shouldn't use radically different APIs from inserting value-initialized objects. Your API also assumes that `T` is a type which can tolerate being uninitialized. We shouldn't make APIs that break the C++ object model; we should make them that actually work with that model.

The goal is this:

T *t = new T[256];
vector
<T> tv(256, ...);

Both of these arrays should perform the same amount of initializing of their respective arrays. If `T` is trivially default constructible, then both of these will be uninitialized.  If `T` has a non-trivial default constructor, then it will be called 256 times in both cases. Because by the rules of C++, that's what `T` requires in order to be a live object.

If you only provide that, you have not solved the complete problem. Sometimes the requirements do include the ability to directly construct a sequence of T objects in place within a vector, in ways that emplace does not support.

That is a problem best solved by allowing `emplace` to construct an object in ways that it does not currently support.

What in particular was a circumstance you were thinking of?

Let's say you want to move a sequence of Ts into a vector<T>, applying a permutation (supplied as a vector<size_t>) as you go, and you can't default construct Ts. You could do that like this with the proposed functionality:

dest.reserve(src.size());
for (size_t i = 0; i != src.size(); ++i)
  // pointer arithmetic questionable, but that's a pre-existing problem with vector
  new (dest.data() + perm[i]) T(std::move(src[i]));
dest.resize_already_initialized(src.size());

Due to the random access order of the destination, you can't do this with emplace.

One (slightly scary) approach would be:
1) permit the user to construct objects in trailing storage of a vector/string, so long as capacity is large enough, and
2) provide a resize_already_initialized(size_t) member to resize the container so that those elements are part of its size, without constructing new Ts over the top of them

Obviously if (1) somehow fails or throws, destroying the elements it created is its problem, and triggering reallocation during (1) would be bad.

I'm not sure why we should encourage (1) happening outside of the presence of (2). Or rather, I don't know why it is necessary to do it that way.

Can you give an example? One that is actually legal C++ under the current object model?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

gmis...@gmail.com

unread,
Jan 10, 2017, 6:43:42 AM1/10/17
to ISO C++ Standard - Future Proposals

I don't know why this required a smart butt remark when I'm obviously here discussing what is required to do that.
But it doesn't happen any easier with you deriding me or the discussion. Where do you get off in doing that? Do you think that assists?

D. B.

unread,
Jan 10, 2017, 6:49:28 AM1/10/17
to std-pr...@isocpp.org
Get down from your high horse. I'm not deriding anything. It was a serious suggestion. You keep talking about how much "I just want" these things, but do not appear to have gathered any real evidence of how/whether they would work. That can be (mis?)read as you wanting others to do it for you, without having convinced them that it would be feasible or worthwhile, or that you have begun to lay any real groundwork.

It was also not so much a comment to you specifically, but to anyone who posts ideas here and then expects that they will just materialise from nowhere (especially in a version of the language whose draft is already closed).

gmis...@gmail.com

unread,
Jan 10, 2017, 8:24:01 AM1/10/17
to ISO C++ Standard - Future Proposals

It's you that's on your high horse because it's you that is making the 'smart' comments!
You have no idea what I do or don't contribute towards C++ or how I contribute so I don't see where you get off being so derisory?

And given I do contribute, I'm entitled to express what I think is important or a must for C++ as anybody else without having to intimately make any such proposal happen that I wish to comment on. It's ridiculous to think otherwise. For example, everybody on the planet thinks C++ must have modules but I can assure you everyone on the planet isn't beavering away working on it! But they'll sure tell you we must have it! So why should I be singled out any different? Are you going to now get on reddit and be derisory to all those folks too?

You seem to have the attitude that because somebody isn't going to make every effort on a subject that can't make any effort or have any opinion. That sounds exactly like a high horse to me! So I think it's you that needs to get off it and stop thinking everyone needs to contribute the way you do that I don't contribute or have to breath the language because you do. I don't. And you shouldn't be so assumptive and 'smart'. Because that isn't.

Nicol Bolas

unread,
Jan 10, 2017, 10:59:56 AM1/10/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
On Tuesday, January 10, 2017 at 1:57:29 AM UTC-5, gmis...@gmail.com wrote:
On Tuesday, January 10, 2017 at 5:19:44 PM UTC+13, Nicol Bolas wrote:
On Monday, January 9, 2017 at 8:57:39 PM UTC-5, gmis...@gmail.com wrote:


Several reasons.

First, `basic_string` is intended to be able to have small string optimization (SSO). This means that strings below a certain size are stored internally rather than allocating memory. Thus, your "detach" function doesn't "detach" something in all cases.

That's not a reason for doing nothing. That's just a description of how things are that doesn't forward anything. I don't know why so many replies are structured like this.

Detach could allocate and copy if it must. If that fails it returns nullptr. Or uninitialized_data_at can do the allocate copy if directed, that can fail anyway so that seems the fine place to do that. We can indicate that in a parameter etc.
There are ways forward here.



Second, `basic_string` and `vector` both allocate memory based on provided allocators. So... how will the user destroy it? They cannot call `delete[]` on it, since it was not allocated with `new[]`. The only way to destroy this object us to use the same allocator that was used to allocate it, or a compatible one. Not only that, the person receiving the pointer has no idea how many objects are in the array, so unless `T` has a trivial destructor, you need to know how many items to destroy. And you need to remember to destroy them in reverse order.

Third, your APIs are really bad. Inserting default-initialized objects shouldn't use radically different APIs from inserting value-initialized objects. Your API also assumes that `T` is a type which can tolerate being uninitialized. We shouldn't make APIs that break the C++ object model; we should make them that actually work with that model.

I said we could enable_if that and that these could be free. You seem to be ignoring that fact or didn't see it. I don't see a problem with the idea.

And C++ already has plenty of 'get outs' for doing what needs to be done if it needs to be done. We should make API's that enable us to do what we need to do. You don't have to call them if you don't need what it offers. So I don't buy your argument.

C++ has ways to do things that are illegal in some circumstances because those tools also permit you to do legal things that you would not otherwise be able to do. I believe that the circumstances where what you're wanting to do is actually legal C++ code can be done in ways that don't require tools that allow you to also do illegal things.

Legal and illegal are just points in time. What is today illegal can often be made legal depending on the will and reasoning.
But something being illegal today in of itself isn't interesting.

... I'm not sure what that has to do with anything I said. Yes, rules can be changed. But unless and until you're actually proposing to change those rules, they are what they are.

For example, a C API cannot create a non-trivial C++ object (if you want to get really technical, a C API cannot begin the lifetime of a C++ object at all, but lets pretend that trivial types can be excepted). As such, you cannot legally hand the memory of a `vector<T>` to a C API to be initialized unless `T` is trivial. Therefore, the ability to default initialize a `vector<T>` is all you need to avoid the performance penalty, since default initialization is a no-op.

Your API would look like this:

vector<T> v;
SomeCAPI(v.uinitialized_data_at(0, n), n);

yes, I'm not attached to the API, but nor do I have a problem with it. I just want the ability.
 

My API would look like this:

vector<T> v(n, std::default_init);
SomeCAPI(v.data(), v.size());

But they would have the same performance: a single allocation of a block of `n` objects, with no initialization of that array.

I'm fine with your API but it's less flexible than my API unless I miss understand what yours implies.
And I feel I'm not appreciating what yours implies  Can you extend v without getting more unwanted initialization with your API? i.e. Is v.resize(10000) going to do the right thing her and not zero fill where n in the initial call is say 1 or 0.

That would be a backwards-incompatible change, so no.

But `v.resize(10000, std::default_init)` works just fine. As would `v.insert(v.end(), 10000, std::default_init)` if you want to add 10,000 default-initialized objects to the end. As would `v.insert(v.begin(), 10000, std::default_init)`, if you want to insert 10,000 default-initialized objects at the beginning. As would `v.push_back(std::default_init)`. And so forth.

See how much more flexible and `vector`-like that is?

So why use an API that is oddball and non-standard looking instead of an API that looks like normal `vector` mechanisms? Your way makes using "uninitialized" data look special-case, like you're cheating or something. My way makes it look normal, just like you had done `new T[n]` or whatever.

I don't find my API that oddball but I'm not hung up on my api, I just want the feature of unintialized allocation. 

Because it is normal. You're not cheating; every step is 100% legal C++. You're not pretending that C APIs can begin the lifetime of C++ objects. You're creating an array of live C++ objects and passing them along to someone else who will trivially copy into them.

I'm not pretending that as far as I know. My API isn't asking C to begin life here. But I'm sure we'll work out whatever misunderstanding I or you have here later.
 
So why do we need an API that looks so alien to how the API currently works?
 
I don't need anything alien. I just want something that gives me unintialized allocation.

That's the fundamental difference between our ideas.

I want to allow `vector` to perform default-initialization on its elements. With my way, the `vector` still contains an array of objects, in accord with the C++ object model; it's just that these objects may be uninitialized objects.

You want to allow `vector` to not construct its elements.  With your way, the `vector` no longer contains objects as defined by the C++ object model.

My way is about bringing the equivalent of `new T[n]` into `vector`. Your way is about bringing C idioms (effectively `malloc` + casting) into `vector`.

That's part of what I mean by "alien". You want to take some other language's idioms and force them into our objects. I want to take our language's current idioms and make them fully available to our objects.

When I mooted what I need, you started talking about language changes as a requirement to progress.

Strictly speaking, you could implement it as a pure library change, even with the syntax I outlined. Overload resolution and adding new types will allow it to work adequately. But if you make it a pure library change, then other code can't work correctly.

For example, if I want to default-initialize the `T` in an `optional<T>`, your way doesn't let me do that. Or if I want to default-initialize the `T` through `make_shared<T>`, it still can't happen. Well, it can't happen without further library changes. And you can keep going on and on and on. What of user-containers; can they be default-initialized too? Now everybody has to add changes to their libraries just to make this work.

Or you can make a proper language change that just handles these cases.

Now yes, my language solution still needs to have some library changes for containers to take full advantage of it. But indirect initialization (`emplace`, `in_place_t` construction, `make/allocate_shared/unique`, etc) will all work without any library changes.

Nicol Bolas

unread,
Jan 10, 2017, 11:14:09 AM1/10/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
On Tuesday, January 10, 2017 at 8:24:01 AM UTC-5, gmis...@gmail.com wrote:

It's you that's on your high horse because it's you that is making the 'smart' comments!
You have no idea what I do or don't contribute towards C++ or how I contribute so I don't see where you get off being so derisory?

And given I do contribute, I'm entitled to express what I think is important or a must for C++ as anybody else without having to intimately make any such proposal happen that I wish to comment on. It's ridiculous to think otherwise.

You have the right to express that you feel something is important. That's fine, and I think D. B. was kinda out of line in trying to upbraid you for it.

However, you do need to make a distinction between "I believe X is critical" and "X is critical". You can argue that something is crucial to C++. But it'd be a lot easier of an argument to make if you have other people around who agree with you.

When I argue that unified call syntax, or something like it, is a vital feature for future C++, I can at least point to the disappointment other people have in the lack of this feature in C++17 as evidence for it. Thus far, the only evidence you have that this is a critical C++ feature is... your word.

Now, I do think being able to default-initialize things really is important. But that doesn't mean we should accept a half-solution (let alone one that's as laced with C-idioms as yours) when we can get a whole one.

For example, everybody on the planet thinks C++ must have modules but I can assure you everyone on the planet isn't beavering away working on it! But they'll sure tell you we must have it! So why should I be singled out any different? Are you going to now get on reddit and be derisory to all those folks too?

There are many differences between modules and your proposal:

1: Modules are a compiler feature. A very, very complex one. Implementing it requires deep knowledge of a complier. Your idea is a pure-library change. Implementing it requires being a C++ programmer.

2: Modules are actively being implemented by 2 major compiler vendors. Your idea is actively being implemented by... nobody.

So suggesting that you provide a proof-of-concept implementation is not unreasonable.

gmis...@gmail.com

unread,
Jan 11, 2017, 4:51:09 AM1/11/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com


On Wednesday, January 11, 2017 at 5:14:09 AM UTC+13, Nicol Bolas wrote:
On Tuesday, January 10, 2017 at 8:24:01 AM UTC-5, gmis...@gmail.com wrote:

It's you that's on your high horse because it's you that is making the 'smart' comments!
You have no idea what I do or don't contribute towards C++ or how I contribute so I don't see where you get off being so derisory?

And given I do contribute, I'm entitled to express what I think is important or a must for C++ as anybody else without having to intimately make any such proposal happen that I wish to comment on. It's ridiculous to think otherwise.

You have the right to express that you feel something is important. That's fine, and I think D. B. was kinda out of line in trying to upbraid you for it.


Totally. On both accounts.
 
However, you do need to make a distinction between "I believe X is critical" and "X is critical". You can argue that something is crucial to C++. But it'd be a lot easier of an argument to make if you have other people around who agree with you.

I agree but I'm not some special offender here so why do I need reminding of this? Maybe you meant to post this to the 'total retardation' guy?

And precisely because there is a one word difference between "we must" and "I believe we must" is why I think we need to stop reminding people generally of this every 5 minutes unless their tone is way out of order. And mine wasn't. It just distracts from the technical issues.

 DB was just doing that just because he's annoyed I haven't presented a proposal that he feels is a detailed to his requirements. That's the real issue so lets talk about that. He needs to get over his viewpoint because he doesn't control how I spend my time.

For the support you mention, I have support for the base of my suggestion: avoiding excess initialization; you and Richard and your thread you kindly linked show that support so I'm not sure what support you are referring to here? Yes we were debating what was best approach for such a proposal and you informed me of yours but that's the point of this forum. So I don't see what problem there was here until DB went out of his way to make a post that was nothing but derisive. So perhaps your reply should have been to him and not me. But maybe he wouldn't do that if he was relieved of some ideas so I'll address that.

We really need to weed this forum of the mind set that people must write a detailed proposal before they can propose or suggest anything on this forum. Or this will keep happening. Sure we would like detailed proposals, but that's a wish not a requirement. So if an idea isn't baked, the reward for that will be it's failure to launch. Let that be enough. People will propose whatever they are capable/comfortable/or bothered to propose anyway. People should assist such "proposals" forward where we they have a mind to and if they don't because they think it's not baked enough then they should ignore it.

We don't need to be carping at every OP because we feel they haven't done enough. We don't know their time or ability constraints and being demanding on them that way is no different to them being demanding on us is it? We just need to accept ideas the way they come and assist them as far as we are capable of being productive in that; and then stop. Or else this forum will read like a moan fest of people on their high horses which it at times often does. And that's where I think DB crossed over.
 

When I argue that unified call syntax, or something like it, is a vital feature for future C++, I can at least point to the disappointment other people have in the lack of this feature in C++17 as evidence for it. Thus far, the only evidence you have that this is a critical C++ feature is... your word.

Now, I do think being able to default-initialize things really is important. But that doesn't mean we should accept a half-solution (let alone one that's as laced with C-idioms as yours) when we can get a whole one.

For example, everybody on the planet thinks C++ must have modules but I can assure you everyone on the planet isn't beavering away working on it! But they'll sure tell you we must have it! So why should I be singled out any different? Are you going to now get on reddit and be derisory to all those folks too?

There are many differences between modules and your proposal:

1: Modules are a compiler feature. A very, very complex one. Implementing it requires deep knowledge of a complier. Your idea is a pure-library change. Implementing it requires being a C++ programmer.

2: Modules are actively being implemented by 2 major compiler vendors. Your idea is actively being implemented by... nobody.

So suggesting that you provide a proof-of-concept implementation is not unreasonable.

This misses the point. There's a time and place for proof of concept. But demanding proof of concept implementation just so you don't have to think too hard about it until then shouldn't be the game. Just don't think about now it if that's how you or anyone (DB) feels, that's cool. I shouldn't need to go hacking a C and C++ memory allocator to prove it's possible for the former to be able to able to de-allocate for the latter - at least for types that don't require destruction - before I can suggest it might be possible or a good idea to the people who actually write these things and hear what they have to say.

They have better existing knowledge and access to the tools and the code bases where they can test these ideas better than I can and they have a much more vested interest in getting the performance win out of that than me. Plus if the idea really has merit, they may get paid for it.

So though you say I have a right to my suggestion, that right isn't worth much if I must have a proof of concept first for my suggestions before I can make them. I don't accept it needs to be a requirement for discussion. Yes it's always nice to have though.

Complexity shouldn't be a factor in allowing an opinion either because complexity is relative to the experience of the people posting and reading and it leads back to randomly smashing people for incompleteness again if we get tied up in that. It's impossible to be even handed in its application anyway.

The recent enum cast proposal is a good example. Will that proposal look at it's end how it was proposed originally? I doubt it. I suspect it will not involve std::optional in the final result at all! But it might. My proposal can easily evolve the same way. So why am I getting flack and not them? The complexity is even less there depending on how far you go.

And I think the enum cast proposal is a great and has total merit so I've assisted with that positively too, so that's another reason why we shouldn't accept derisory attacks because it makes people not want to bother anywhere. People should just assist with what's presented and help complete the incomplete if they want to, or stay clear.

We must get this forum to a point where we accept casual proposals or proposal related comments without insisting investment beyond what the OP wants to make. If a proposal fails because for lack of implementation so be it. It's better than arbitrary moaning at an OP so they don't even engage at all and it fails earlier with less even to take forward by someone else. We need to change our expectations.

This forum is a "proposals" site and wg21 site is the proposal site. Lets set expectations to match that reality. We need to let contributors contribute and just be happy that they are contributing. It doesn't mean you can't challenge a bad idea or offer a better way, but just stop moaning something isn't baked enough to your liking. Just help in the baking which is what community is supposed to be about or stay back. That's my view. I hope the isocpp site operators will put some wording on the site to assist this reality being acknowledged so it stops this repetitive cycle.

Matthew Woehlke

unread,
Jan 11, 2017, 11:57:07 AM1/11/17
to std-pr...@isocpp.org
On 2017-01-11 04:51, gmis...@gmail.com wrote:
> I shouldn't need to go hacking a C and C++ memory allocator to prove
> it's possible for the former to be able to able to de-allocate for
> the latter

Um... good luck with that. Given that, last I knew, it was still
possible to have multiple versions of the C runtime - with incompatible
allocators - participating in a process, I doubt you're going to have
much luck getting them all to play nice by introducing the C++ allocator
to the mix. Never mind that some programs may be using custom allocators.

There's a very good reason why transfer of memory ownership almost
always (at least in code that isn't broken by design) involves also
telling the receiver how to release the memory.

That said, if you want to propose a mechanism that *includes* getting a
pointer to a function that can free your "detached" memory, you might
have better luck...

> So though you say I have a right to my suggestion, that right isn't worth
> much if I must have a proof of concept first for my suggestions before I
> can make them. I don't accept it needs to be a requirement for discussion.
> Yes it's always nice to have though.

I think you might be reading too much into this. You are making a claim.
Others are disbelieving your claim. The point being made is that just
repeating yourself over and over is not persuasive. Otherwise, all we
have, on either side, is opinions, and I am just as welcome to mine as
you are to yours.

Also... *nothing* is stopping you from moving ahead with your proposal
anyway. Maybe the committee will think it's a fabulous idea and move
forward with it anyway. Maybe they'll have the same reaction:
unconvinced without further evidence. Very little¹ that happens on this
forum reflects how you *must* proceed. Rather, it serves as an
approximation of how the committee is *likely* to respond to a proposal.
Ignore or abide by that at your own risk.

(¹ Comments made by committee members are of course not to be set aside
lightly, as they will almost certainly happen in actual committee also.)

> The recent enum cast proposal is a good example [...] why am I
> getting flack and not them?

I would disagree with the claim that Maciej is not getting flack :-).

> People should just assist with what's presented and help complete the
> incomplete if they want to, or stay clear.

Here, I am not sure I agree. There is a cost to dealing with bad
proposals, especially by the time they get to an actual committee
meeting. Allowing a bad proposal to get that far can end up wasting a
lot more time than if it was killed off early.

I also am not convinced that allowing a terrible proposal to make it all
the way to committee isn't doing the *proposer* a disservice, as well.
If I have an idea that is really terrible, I want to know that people
feel that way. At least so I'm prepared for it at committee, but also so
that maybe I'm not wasting time on a proposal that has no chance of success.

--
Matthew

G M

unread,
Jan 11, 2017, 6:13:30 PM1/11/17
to std-pr...@isocpp.org
Nobody is disbelieving my claim, The emphasis of my posts are about two things: 1) uninitialized allocation which there is complete agreement nearly on the need for and 2) how one should be able to present that proposal/idea without facing derision.

If you are talking about some technical claim where there is disbelief, you might be focusing on the allocator part, but if you look at my comments to Nicol, I made it explicitly clear that's not a key aspect of my proposal.  So there is no disagreement there.

To save you looking, I was saying that C/C++ sharing a de-allocator at least for pods could be of mutual gain and could be a 'nice to have' thing that is worthy of consideration by the Committee but I have no hope in hell of doing that myself. More to the point I should be able to ask those in the know about that getting unhelpful responses to the question though.

So *now* at the risk of repeating myself...
 
What I am saying is:
It should be able to "propose" something notionally like I think we need 'uninitialized allocation now' how about this...'

And get back responses like this:
'yes that seems possible but it will be hard because of Y....' (which your comment said re:allocators) OR
'no because Y seems to be technically un-achievable because of Z'.

Instead of this:
'no it can't be done because we don't allow that today (no further commentary)'
'no I don't think that's possible, give me a proof of implementation that shows that it is (no commentary)'
'you're idea is complete. don't come back until you have proof it can be done.' (especially this)
'you are being demanding go away'

The former set of replies takes us forward (even to a meaningful halt) and is encouraging.
The latter is utterly pointless.

People will come here to see if their assertions make sense. They don't want to be told that they can't make these assertions without having to already know the answer (i.e. have proof of concept already), as if they were that sure they'd not need to post here at all and they'd just make contact with wg21 directly.
 

Also... *nothing* is stopping you from moving ahead with your proposal
anyway. Maybe the committee will think it's a fabulous idea and move
forward with it anyway. Maybe they'll have the same reaction:
unconvinced without further evidence. Very little¹ that happens on this
forum reflects how you *must* proceed. Rather, it serves as an
approximation of how the committee is *likely* to respond to a proposal.
Ignore or abide by that at your own risk.

No, nothing is stopping anybody, but we should we encourage discouragement?
 

(¹ Comments made by committee members are of course not to be set aside
lightly, as they will almost certainly happen in actual committee also.)

> The recent enum cast proposal is a good example [...] why am I
> getting flack and not them?

I would disagree with the claim that Maciej is not getting flack :-).

> People should just assist with what's presented and help complete the
> incomplete if they want to, or stay clear.

Here, I am not sure I agree. There is a cost to dealing with bad
proposals, especially by the time they get to an actual committee
meeting. Allowing a bad proposal to get that far can end up wasting a
lot more time than if it was killed off early.

Nobody needs waste their time. If someone can't move a "proposal' forward, say nothing.


I also am not convinced that allowing a terrible proposal to make it all
the way to committee isn't doing the *proposer* a disservice, as well.
If I have an idea that is really terrible, I want to know that people
feel that way. At least so I'm prepared for it at committee, but also so
that maybe I'm not wasting time on a proposal that has no chance of success.


That's fine, I'm not arguing you can't challenge a proposal, I'm trying to alter how the challenges come so that people aim to focus on the essence of an idea, incomplete as it maybe, expecting that it will need to grow and morph a bit, and that's what they are assisting with, not just take something as it is and rip it up or get derisory each time. Encourage the essence of the idea.

The essence of my proposal was good: uninitialized allocation. As it turns out boost has that feature I want already so there's no doubt it's good. *And we were progressing to that point here until I got derision because someone was upset about incompleteness.*

*If I'd have gone away and spent ages coming up with what boost already did, I'd have wasted my time as far as I am concerned.* So we need to let incomplete proposals roll without unwarranted hassle for that reason too. This discussion spread awareness and identified what I wanted existed, so why should I take flack for engaging to discover that.

Now I just hope we get this feature as boost has it. I'd love it to get into C++17, but I accept it might be too late.
 

--
Matthew

--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/ofyByk1VorU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

G M

unread,
Jan 11, 2017, 6:37:42 PM1/11/17
to std-pr...@isocpp.org
On Thu, Jan 12, 2017 at 5:57 AM, Matthew Woehlke <mwoehlk...@gmail.com> wrote:
On 2017-01-11 04:51, gmis...@gmail.com wrote:
> I shouldn't need to go hacking a C and C++ memory allocator to prove
> it's possible for the former to be able to able to de-allocate for
> the latter

Um... good luck with that.

I should add that so far the enum cast proposal is a model of what I do want to see.

1. Somebody has the essence of a good idea.
2. Possibly not be best API exactly as proposed, but it's of no concern. The idea is good.
3. So everyone rallies around and morphs it into something to with a better API.
4. OP writes it all up and submits a proposal.

No derision, no concern about incompleteness. Complete the incomplete.
Same thing could have happened here. But boost/nicols proposal has what I want and it revealed that so I'm happy.So this thread can die unless people want to use it for ironing out anything nicol or boost is proposing that they don't like.

It might be nice to hear some comments on what the way forward is regarding boost and C++17/next.
i.e. I assume that hasn't actually been proposed for standardisation yet? Are they wanting to wait?

Nicol Bolas

unread,
Jan 11, 2017, 7:33:14 PM1/11/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com

But there is disagreement on the need for this. Namely, I disagree.

Note that my idea is very much not about "uninitialized allocation"; it is about default initialization. Those aren't the same thing, and the difference is a matter of what is legal, standard C++ and what is not.

Your proposal is to make C idioms into valid C++. Your proposal is not legal C++; not unless you make changes to the C++ object model. And you have not specified what those changes need to be. Presumably it would be "do whatever it takes to make this code work," which is not helpful when making a proposal.

My proposal is to make valid C++ idioms accessible through `vector` (and other things).

Essentially, the only things we agree on are the problem domain: avoiding value initialization for objects whose contents are going to be overwritten.
 
Also... *nothing* is stopping you from moving ahead with your proposal
anyway. Maybe the committee will think it's a fabulous idea and move
forward with it anyway. Maybe they'll have the same reaction:
unconvinced without further evidence. Very little¹ that happens on this
forum reflects how you *must* proceed. Rather, it serves as an
approximation of how the committee is *likely* to respond to a proposal.
Ignore or abide by that at your own risk.

No, nothing is stopping anybody, but we should we encourage discouragement?

If it is warranted, then yes. With the exception of what D. B. said, I have yet to see any criticism of your idea that is not unwarranted.

On Wednesday, January 11, 2017 at 6:37:42 PM UTC-5, G M wrote:
I should add that so far the enum cast proposal is a model of what I do want to see.

1. Somebody has the essence of a good idea.
2. Possibly not be best API exactly as proposed, but it's of no concern. The idea is good.
3. So everyone rallies around and morphs it into something to with a better API.
4. OP writes it all up and submits a proposal.

Well, let's point out the differences between that thread and this one.

1: The OP's idea was perfectly functional as originally stated. There were no defects of design, only questions of performance and so forth. By contrast, your idea violated the C++ object model and had memory allocation concerns. It was not nearly as well conceived as the other thread.

2: When others suggested interface changes, the OP did not respond in a defensive way.

3: At no time did the OP of that thread make the claim that their proposal was so important that it needed to be stuck into C++17. That waiting 3 years or more would be intolerable.

It seems to me that what you get out of this forum is based on what you put into it. The more effort you put into your ideas before making them, the better your reception will be.

gmis...@gmail.com

unread,
Jan 11, 2017, 11:43:01 PM1/11/17
to ISO C++ Standard - Future Proposals, gmis...@gmail.com
I don't see it that way.

I wasn't "defensive" about changing my interface. I didn't even see the interface as a big deal at this moment. It was acceptance of the functionality that I was gauging. I just presented an API that I felt delivered the functionality I wanted. But then you (or somebody) opened with saying I didn't have support, which I took to mean for the functionality so I was defending that. The functionality IS important. You just presented your agreement as non agreement. That was just confusing.

Then there was talk about alien interfaces, which is subjective so of course I'm going to defend something against abstract or else I've got nothing. And then you presented an actual an actual API, but it was one method call that was insufficient for what I needed. So of course I'm going to defend mine against yours while yours doesn't do what I want! That isn't being defensive,

Not least of all because I continued inquiring about if there was more to your API then you initially presented. And importantly I continued to be polite about.

If I was defensive I would be neither polite nor inquiring. And once you unfurled the extent of your API and I saw it did what I wanted, I accepted it as a result I'm happy with. You can't ask for more than complete acceptance of an alternative once it's actually presented! I don't see anything defensive about that process. That just is the process.

I don't see any problem with that, that's what a discussion is about. It was the derision and the reason behind it that I objected to and I still do. Yours/the boost proposal covers the essence of what I wanted to achieve so I don't see there being any disagreement.

If you're supportive to the essence of something, you should sound like it.

Reply all
Reply to author
Forward
0 new messages