Thursday, November 24, 2016

Digest for comp.lang.c++@googlegroups.com - 25 updates in 6 topics

Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 24 01:07PM

On Thu, 24 Nov 2016 12:50:47 +0100
> similar enough): "C memory object and value semantics: the space of
> de facto and ISO standards"
> https://www.cl.cam.ac.uk/~pes20/cerberus/notes30.pdf
 
This is a workaround for microsoft's compiler for its x86/64 products.
You can do whatever that compiler and/or the x86/64 platform will
accept. This also happens to be microsoft's suggestion (although I
cannot say that I now remember what size of integer value they
recommend).
 
There are two issues, alignment and strict aliasing. On alignment,
with x86/64 that only goes to speed of access and not correctness. An
initial int value will in practice be fine. If you remain worried
about it after testing, you can use an initial segment size of
alignof(std::max_align_t) in which to put your integer value, which is
8 bytes on 32-bit windows and 16 bytes on 64-bit.
 
Strict aliasing is not an issue. Just don't write or read the memory
block's initial integer value in a way which breaks C++'s strict
aliasing rules, that is, manipulate or read the initial integer value
via char* or via std::memcpy()[1].
 
What else do you think is problematic?
 
Incidentally gcc is irrelevant to this. It provides the correct value
to operator delete[] to begin with.
 
Chris
 
[1] This is being pedantic. After casting operator delete[]'s void*
argument to some other pointer type, type information about the dynamic
type of the content is absent and indeed all objects formally in that
block have already been destroyed, so microsoft's compiler cannot (and
anyway will not) optimize against it. It is just a block of bytes at
that stage, awaiting release to the memory pool or whatever else the
custom allocator does.
mark <mark@invalid.invalid>: Nov 24 04:31PM +0100

On 2016-11-24 14:07, Chris Vine wrote:
> strict aliasing rules, that is, manipulate or read the initial
> integer value via char* or via std::memcpy()[1].
 
> What else do you think is problematic?
 
Your delete receives a pointer to the middle of the memory block. If you
do pointer arithmetic on that to get a pointer to the beginning of your
memory block, you have undefined behavior.
 
> [1] This is being pedantic.
 
This is not being pedantic. Some compiler developers interpret the
standard in an extremely aggressive (user-unfriendly) way and don't care
if they break real-world code if they might get some tiny performance
improvement. Maybe you can get away with this, if you restrict your code
exclusively to VC++, but with GCC or CLang I wouldn't count on it.
 
> pointer type, type information about the dynamic type of the content
> is absent and indeed all objects formally in that block have already
> been destroyed,
 
The pointer origin and original type can still be tracked in a lot of
cases and the compiler will be able to prove where the pointer came from.
 
The delete[] operator will receive a pointer that pointed to some array
S[]. The only pointer math that the standard allows is within the bounds
of S[] and one beyond. Casting to char* doesn't allow you to go outside
the bounds of S[]. Doing math on uintptr_t doesn't change that.
 
> so microsoft's compiler cannot (and anyway will not) optimize against
> it.
 
VC++ is less aggressive with optimizations relying on undefined
behavior, but is that guaranteed somewhere?
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 24 04:36PM

On Thu, 24 Nov 2016 16:31:39 +0100
> On 2016-11-24 14:07, Chris Vine wrote:
[snip]
 
> Your delete receives a pointer to the middle of the memory block. If
> you do pointer arithmetic on that to get a pointer to the beginning
> of your memory block, you have undefined behavior.
 
This is wrong. See below.
 
> performance improvement. Maybe you can get away with this, if you
> restrict your code exclusively to VC++, but with GCC or CLang I
> wouldn't count on it.
 
There is no getting away with anything if you access the integer value
with unsigned char* or std::memcpy(). See below.
 
But in any event, as I have already said, this is only concerned with
VC++. There is no way you would bother with this rigmarole with either
gcc or clang, which get operator delete[] right in the first place.
 
> the bounds of S[] and one beyond. Casting to char* doesn't allow you
> to go outside the bounds of S[]. Doing math on uintptr_t doesn't
> change that.
 
You are wrong about this. operator new[] and operator delete[] know
nothing of types, whether array S[] or anything else. All they know
about is raw bytes of allocated memory passed by void*. They are the
equivalent of malloc() and free() (and many global operator new[]
and operator delete[] just call malloc() and free() and do nothing
else).
 
I think you may be confusing this with the new[] and delete[]
_expressions_, which do know about types and will construct or receive a
typed array (albeit in the case under discussion beginning 4 bytes off
the beginning of the raw memory originally allocated by operator
new[]). By the time you get to operator delete[], the delete[]
_expression_ has already destroyed all the objects in that typed array.
All that is left as an object is the integer value that operator new[]
originally put at the beginning of the allocated memory.
 
You are doing three things in this putative operator delete[]:
 
(i) you are working back to the beginning of the memory block
originally allocated by your custom operator new[]. Using pointer
arithmetic with unsigned char* is guaranteed by the standard to give the
correct result and I cannot think why you think otherwise. At no point
is any pointer going beyond the memory block allocated by operator
new[], so there can be no undefined behaviour.
 
(ii) you are then either using array addressing with unsigned char* or
using std::memcpy() to copy the initial 4 bytes into a local unsigned
int. If you are doubtful about the first, see §3.10/10 of C++11/14,
last bullet. In practice use std::memcpy(), as in all decent compilers
the call will be optimized out - it is the recommended way of dealing
with aliasing for this kind of case.
 
(iii) you then deallocate this raw block of memory with your custom
deallocator.
 
> > against it.
 
> VC++ is less aggressive with optimizations relying on undefined
> behavior, but is that guaranteed somewhere?
 
If you use either unsigned char* or std::memcpy() the aliasing is
entirely compliant and guaranteed to work. See §3.10/10 of C++11/14 as
regards unsigned char*.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Nov 24 05:28PM

On Tue, 2016-11-22, Mark Blair wrote:
 
>>>> What kind of scenarios are there with modern hardware and software where
>>>> you are using this kind of thing?
 
>>> It's very useful when used with shared memory.
 
...
 
> On Linux, between separate processes that share structured data. In one
> case we have a Java GUI that uses JNI to interface to data populated
> from a C++ daemon.
 
I think I'd tend to treat that memory as an unstructured buffer, or at
most a dumb struct. The object wrapping it could have pointer to the
buffer, rather than be created using placement new. The class would
have to be very carefully written anyway.
 
I'm like Christopher -- never used placement new, never think I will.
If I have to, I'll read up on it, like with so many other language
features.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
mark <mark@invalid.invalid>: Nov 24 07:04PM +0100

On 2016-11-24 17:36, Chris Vine wrote:
> typed array (albeit in the case under discussion beginning 4 bytes off
> the beginning of the raw memory originally allocated by operator
> new[]).
 
No, I don't.
 
> _expression_ has already destroyed all the objects in that typed array.
> All that is left as an object is the integer value that operator new[]
> originally put at the beginning of the allocated memory.
 
That doesn't change the fact that it was an S[]. If all the code is
available inline, the compiler can infer that it was an S[], it didn't
change the type to something else and it thus cannot be a pointer into a
larger char array. And you cannot leave the bounds of S[].
 
There is no special allowance for pointer math for delete[] in the standard.
 
> originally allocated by your custom operator new[]. Using pointer
> arithmetic with unsigned char* is guaranteed by the standard to give the
> correct result and I cannot think why you think otherwise.
 
It gives the numerically correct result.
 
> At no point is any pointer going beyond the memory block allocated by
> operator new[], so there can be no undefined behaviour.
 
It goes beyond the bounds of S[] - which it was just previously. How
does that pointer that pointed to S[] magically change to a pointer for
the outer block? That it was auto-cast to void* doesn't change it's
history or provenance.
 
What do you think the dynamic type of a pointer to an S[] is over its
lifetime (after construction, after the destructor has run, when the
deallocation function is called)? If the dynamic type changes, how does
that happen? Where in the standard is that spelled out?
 
Do you think your pointer math is valid over the entire lifetime of S[]
or only after the destructor has run?
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 24 06:22PM

On Thu, 24 Nov 2016 19:04:01 +0100
> does that happen? Where in the standard is that spelled out?
 
> Do you think your pointer math is valid over the entire lifetime of
> S[] or only after the destructor has run?
 
You say you are not confusing operator new[] and delete[] with the
new[] and delete[] expressions, but you are contradicting yourself
because you plainly are. operator new[] and operator delete[] do not
deal in arrays. They deal in bytes of memory. End of story.
legalize+jeeves@mail.xmission.com (Richard): Nov 24 06:27PM

[Please do not mail me a copy of your followup]
 
Louis Krupp <lkrupp@nospam.pssw.com.invalid> spake the secret code
>object, whether it's static or automatic or allocated by something
>other than malloc(), you can use placement new to run the object's
>constructor with calling malloc().
 
I've also seen it used to ensure that the memory allocation happens
inside a DLL but the constructor runs in whatever code is creating the
instance of a type defined by the DLL.
 
This is a Windows annoyance of how DLLs behave, but if you have this
problem then it is something you have to deal with. Another
alternative is to expose only interfaces with virtual d'tors and
provide factory functions for creating instances. (Gee, sounds like
COM!)
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Nov 24 06:38PM

[Please do not mail me a copy of your followup]
 
someone@somewhere.net spake the secret code
 
>What does one use shared memory for? Faster IPC? What are some examples?
>where you've used it?
 
Yes, faster IPC. If two processes are on the same machine, they don't
need sockets to talk, just a shared memory segment. If you're using
some flavor of unix, the X Window System has had this for a very long
time to enable more efficient communication between clients running on
the same machine as the display server.
 
>Only virtual addresses that map to regions of a file. If that is
>correct, perhaps, this is the reason I have not come across this, being
>a Windows guy.
 
It's the same thing under a different name:
<https://msdn.microsoft.com/en-us/library/windows/desktop/aa366551(v=vs.85).aspx>
 
MSDN calls it "memory-mapped files that the system paging file
stores". If you look at that example, there is no actual file
specified, which tells Windows "use the paging file", which is just a
slightly obtuse way of saying "give me a piece of virtual memory as a
file". That's because Windows is going to expose the sharing through
file handles so we need some way of getting a file handle for a chunk
of virtual memory in order to share a memory segment. They use a
"filename" (Global\\MyFileMappingObject) to identify the segment between
the two processes.
 
There are analogous APIs in unix for all of this and the result is
basically the same. You have a chunk of memory that can be shared
between two processes. For System V shared memory segments (I don't
think BSD ever came up with something that did the same thing), you
want to look at functions shmget, shmat, shmctl, etc.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Nov 24 06:41PM

[Please do not mail me a copy of your followup]
 
Jorgen Grahn <grahn+nntp@snipabacken.se> spake the secret code
>most a dumb struct. The object wrapping it could have pointer to the
>buffer, rather than be created using placement new. The class would
>have to be very carefully written anyway.
 
All the instances I've seen treat the chunk of memory as a binary
buffer into which structures are serialized/deserialized.
 
Going back to the X Window System situation, this makes the perfect
place for the client to write its protocol stream and for the server
to read the protocol stream. They just don't communicate the protocol
bytes over a socket.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
mark <mark@invalid.invalid>: Nov 24 08:04PM +0100

On 2016-11-24 19:22, Chris Vine wrote:
> new[] and delete[] expressions, but you are contradicting yourself
> because you plainly are. operator new[] and operator delete[] do not
> deal in arrays. They deal in bytes of memory. End of story.
 
There are no bytes of memory in the standard.
 
Pointer arithmetic is only allowed within array bounds. Read the
standard, "5.7 Additive operators [expr.add]".
 
Either that void* is a pointer into an array of some type (that array
must include your size variable) or your pointer math is undefined
behavior.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Nov 24 08:15PM

On Thu, 24 Nov 2016 20:04:47 +0100
mark <mark@invalid.invalid> wrot
[snip]
 
> Either that void* is a pointer into an array of some type (that array
> must include your size variable) or your pointer math is undefined
> behavior.
 
Despite all the previous things you have posted this is an interesting
point. I suppose the first thing to say is that contrary to what you
say there are bytes of memory in the standard. They are referred to as
a "block of storage" having a length in bytes.
 
Let's take the return value of operators new and new[]. §3.7.4.1/2 of
the standard says:
 
"If it is successful, it shall return the address of the start of a
block of storage whose length in bytes shall be at least as large as
the requested size. ... The pointer returned shall be suitably aligned
so that it can be converted to a pointer of any complete object type
with a fundamental alignment requirement (3.11) and then used to access
the object or array in the storage allocated (until the storage is
explicitly deallocated by a call to a corresponding deallocation
function)."
 
It therefore provides for the block of storage returned by void* by
operator new/new[] to be convertible to, amongst any other type, pointer
to unsigned char or pointer to unsigned int and then used to access an
object or array of objects of those types in the storage. It must
allow this, or the there would be no purpose in allocating memory in
the first place. Upon constructing objects in that block of storage,
they becomes assessible and, if it is an array, §5.7 applies.
 
Objects or arrays are placed into the block of storage by placement new
or (for trivial types) just by memcpy()ing it in. That is what the
new/new[] expression (as opposed to operator new) does. Arguably on the
most pedantic level, when implementing the microsoft workaround you
should place the integer value into the memory as an array of char, so
that subsequently using pointer arithmetic on it would then meet the
requirements of §5.7.
 
As a matter of fact the microsoft workaround does not (as I recall it)
require one to go to the additional trouble of converting to an array of
char. The overarching point on that is, as I have now said for the
third time, that this is only concerned with VC++ and is the way they
deal with the issue. One can therefore take it that, with VC++, it
works. And for the reasons mentioned it seems to me that it is
required to work.
Paavo Helde <myfirstname@osa.pri.ee>: Nov 24 10:19PM +0200

On 24.11.2016 13:50, mark wrote:
> "C memory object and value semantics: the space of de facto and ISO
> standards"
> https://www.cl.cam.ac.uk/~pes20/cerberus/notes30.pdf
 
The technique described by Chris is actually often used by compilers
themselves. When you delete[] an array allocated via custom memory
allocator, the compiler needs to know how many destructors to call. How
does it know? Simple, it asks for 4 or 8 bytes more memory from your
custom allocator, stores the object count in the beginning of the block
and shifts the pointer before returning it from the new[] - that's the
same technique as described by Chris.
 
Of course, implementation can do things which are forbidden for mere
mortals, but it still shows the memory is not considered as pure array
of N objects.
 
Demo: MSVC2013:
 
#include <iostream>
#include <string>
 
class A {
public:
void* operator new[](size_t n) {
void* p = malloc(n);
std::cout << "Allocating " << n << " bytes at " << p << "\n";
return p;
}
void operator delete[](void* p) {
std::cout << "Releasing " << p << "\n";
}
std::string s;
};
 
int main() {
std::cout << "Creating array of 10 strings (" <<
10*sizeof(std::string) << " bytes)\n";
A* a = new A[10];
std::cout << "Array starts at " << a << "\n";
delete[] a;
}
 
 
Creating array of 10 strings (400 bytes)
Allocating 408 bytes at 00000000000EB5E0
Array starts at 00000000000EB5E8
Releasing 00000000000EB5E0
Jerry Stuckle <jstucklex@attglobal.net>: Nov 24 03:58PM -0500

On 11/24/2016 1:38 PM, Richard wrote:
> some flavor of unix, the X Window System has had this for a very long
> time to enable more efficient communication between clients running on
> the same machine as the display server.
 
Don't forget if any process writes to the shared memory, all access to
the shared memory must be protected by mutex semaphores. That slows
things down a bit - but it's still a lot faster than any other IPC.
 
--
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
Louis Krupp <lkrupp@nospam.pssw.com.invalid>: Nov 24 09:46AM -0700

>[https://www.amibroker.com/guide/afl/strright.html]
 
>-Lenght is a lenght (number) of the sting of the symbol (StrLeng)
>http://www.amibroker.com/guide/afl/strlen.html
 
Your program, as you last posted it:
 
AB = CreateObject("Broker.Application");
sts = AB.Stocks();
Qty = sts.Count;
 
for( i = Qty - 1; i >= 0; i = i - 1 )
{
st = sts.Item( i );
Ticker = st.Ticker;
printf("changing " + Ticker + "\n" );
Length = StrLen(Ticker );
 
** 'Length' is now set to the length of the symbol
 
if( StrFind(Ticker, "TO:") )
st.Ticker= "TC-"+StrRight(Ticker,Lenght+3);
 
** 'Lenght' is not the same as 'Length'. My guess is that 'Lenght' is
** zero.
**
** I would try this:
** st.Ticker= "TC-"+StrRight(Ticker,Length - 3);
 
}
 
Let me know what happens.
 
Louis
legalize+jeeves@mail.xmission.com (Richard): Nov 24 06:24PM

[Please do not mail me a copy of your followup]
 
Lino <lino@net.com> spake the secret code
 
>Script Below
 
Wrong newsgroup. Try a forum for Windows Scripting.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Nov 24 06:23PM

[Please do not mail me a copy of your followup]
 
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
 
>Just trust me on this.
 
Or just KILL file Stefan Ram and this newsgroup becomes more enjoyable.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
bitrex <bitrex@de.lete.earthlink.net>: Nov 24 11:13AM -0500

From this it looks like boost::any/std::any currently only supports
objects which are copy-constructible, and not simply move-constructible.
 
https://www.reddit.com/r/cpp/comments/4fyt3v/why_doesnt_stdany_support_move_only_types/
 
I noticed from the boost/any.hpp that if I'm using C++11 or greater, the
code first checks to see if the class is copy-constructible, and if it
is it then checks the C++ version to see if it's C++11 or greater
(#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES) and it looks like it then
uses the move constructor anyway.
 
That's a bit annoying. Is writing a wrapper class the only workaround?
"Öö Tiib" <ootiib@hot.ee>: Nov 24 09:07AM -0800

On Thursday, 24 November 2016 18:14:07 UTC+2, bitrex wrote:
> (#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES) and it looks like it then
> uses the move constructor anyway.
 
> That's a bit annoying. Is writing a wrapper class the only workaround?
 
Why it is annoying?
 
Things that are not copyable are usually passed around by additional
indirection (like smart pointer or handle) anyway. So one workaround
is to put that thing into that 'any' instead of object itself.
 
Other workaround is not to use 'any'. It is indeed safer than things
like void* or ellipsis function argument but so what? I never need
these either.
bitrex <bitrex@de.lete.earthlink.net>: Nov 24 12:35PM -0500

On 11/24/2016 12:07 PM, Öö Tiib wrote:
 
> Things that are not copyable are usually passed around by additional
> indirection (like smart pointer or handle) anyway. So one workaround
> is to put that thing into that 'any' instead of object itself.
 
Hmm, yes. I guess that would make sense, wouldn't it ;-)
 
> Other workaround is not to use 'any'. It is indeed safer than things
> like void* or ellipsis function argument but so what? I never need
> these either.
 
It looks like it's about 1000 times slower in practice than say,
boost::variant too.
 
I was mostly hoping to use it as an argument to a constructor so I could
just pass in a ref to (any) object and extract a particular method from
that object into a boost::function. Should work just fine passing in the
smart pointer I guess
JiiPee <no@notvalid.com>: Nov 24 12:42PM

Ok, this was pretty clear explanation. So in this occasion its ok
because MFC uses that convention.
 
On 24/11/2016 10:08, Chris Vine wrote:
Jerry Stuckle <jstucklex@attglobal.net>: Nov 24 09:38AM -0500

On 11/24/2016 7:35 AM, JiiPee wrote:
> the function will destroy it. Is there a risk here and confusion that if
> the user forgots that its self deleted? How does the user remember that
> in this occasion the object will be self-destroyed?
 
It's called documentation. And a user can forget anything is deleted.
It has nothing to do with whether it is self-deleted or not.
 
You must also remember that this is in response to an asynchronous call
from within Windows, not from the application itself. The object cannot
be deleted before this because it must be there to handle the message.
And the object is already considered "gone" to the rest of the application.
 
--
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
Paavo Helde <myfirstname@osa.pri.ee>: Nov 24 06:03PM +0200

On 24.11.2016 14:35, JiiPee wrote:
>> should never be referenced again (and isn't in MFC).
 
> but even if it is not a smart pointer, the user must still *know* that
> the function will destroy it. Is there a risk here and confusion that if
 
Confusion is the middle name of MFC! :-)
 
> the user forgots that its self deleted? How does the user remember that
> in this occasion the object will be self-destroyed?
 
What do you mean by "user"? If you mean the programmer, then he is
supposed to follow the documentation. If it is the calling code, then
this calling code is MFC which *assumes* that dialog will be dead after
OnNcDestroy(). This function should not be called explicitly from
elsewhere than MFC.
 
Besides, MSDN documentation says that 'delete this;' should be put into
virtual PostNcDestroy() override which is called from the default
implementation of OnNcDestroy(), so whoever placed it directly in
OnNcDestroy() already violated the conventions and caused confusion indeed.
 
"https://msdn.microsoft.com/library/49a832ee-bc34-4126-88b3-bc1d9974f6c4.aspx#cwnd__onncdestroy"
Paavo Helde <myfirstname@osa.pri.ee>: Nov 24 06:11PM +0200

On 24.11.2016 14:37, JiiPee wrote:
>> With legacy frameworks like MFC one needs to use their conventions of
>> course, and if this requires writing 'delete this;' then so be it.
 
> You would not mix the modern C++ with MFC?
 
Sure one can mix code, but one cannot redesign MFC to use another
ownership model for its objects.
JiiPee <no@notvalid.com>: Nov 24 04:50PM

On 24/11/2016 16:03, Paavo Helde wrote:
 
>> but even if it is not a smart pointer, the user must still *know* that
>> the function will destroy it. Is there a risk here and confusion that if
 
> Confusion is the middle name of MFC! :-)
 
hehe. Well, I still like it (even if its not perfect/pretty). Remember,
i have lived my whole programming life with it!! And I dont like
divorces, hehe. People take divorces too easily.. I am a faithfull man :).
 
 
>> the user forgots that its self deleted? How does the user remember that
>> in this occasion the object will be self-destroyed?
 
> What do you mean by "user"?
 
the one who uses that Dialog. The programmer who writes code to use that
dialog.
 
> If you mean the programmer, then he is supposed to follow the
> documentation. If it is the calling code, then this calling code is
> MFC which *assumes* that dialog will be dead after OnNcDestroy().
 
but the question is that do we delete the dialog object inside the
dialog class (at OnNcDestroy call) or from the class where it is
created. But seems like Microsoft supports this... below:
 
> into virtual PostNcDestroy() override which is called from the default
> implementation of OnNcDestroy(), so whoever placed it directly in
> OnNcDestroy()
 
Good catch. Oh, now i get it. I was capturing the message directly, but
I should use the virtual call. Ok, but online many people seem to use
directly OnNcDestroy(); message function.
 
> already violated the conventions and caused confusion indeed.
 
> "https://msdn.microsoft.com/library/49a832ee-bc34-4126-88b3-bc1d9974f6c4.aspx#cwnd__onncdestroy"
 
but the confusion I mentioned is more like with the delete this;
 
mark <mark@invalid.invalid>: Nov 24 01:38PM +0100

On 2016-11-24 13:09, Christopher J. Pisz wrote:
> Deallocated 16 bytes for a struct std::_Container_proxy
 
> Why are 16 bytes allocated before space for the actual data I am putting
> into the std::vector and what is a container_proxy?
 
Probably iterator tracking / debugging:
<https://hadibrais.wordpress.com/2013/11/13/dissecting-the-c-stl-vector-part-2-constructors/>
 
> What is the second argument in pointer allocate(size_type n,
> const_pointer = 0) ?
 
> What is the second argument in void deallocate(pointer p, size_type) ?
 
http://en.cppreference.com/w/cpp/memory/allocator
 
> {
> return static_cast<size_type>(-1) / sizeof(value_type);
> }
 
For unsigned types, -1 is equivalent to numeric_limits<size_type>::max().
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: