The following code block works fine:
{
int* x = new int(15);
*x = 25;
delete x;
}
the following code block does not work. Please help.
{
int * x = new int[3];
*(x + 0) = 1;
*(x + 1) = 2;
*(x + 2) = 4;
//delete x;
delete [] x;
}
How is it not working? (It looks fine)
--
Truth,
James Curran
http://www.NJTheater.com (Professional)
http://www.NovelTheory.com (Personal)
http://www.BrandsForLess.com (Day Job)
{
int* b = new int[3];
*(b) = 12;
*(b + 1) = 15;
*(b + 2) = 88;
cout << *(b) << endl << *(b++) << endl << *(b + 2) << endl;
//TODO: get this to work ... or understand this better.
//For some reason this ending statement does not work!!!!!
delete b;
}
"James Curran" <james...@mvps.org> wrote in message
news:eAE4JjlIAHA.285@cppssbbsa04...
In the scenario you paint below, you are both performing a memory
overwrite on space that you do not own *and* you are deleting a pointer that
has changed. For a moment, consider that 'b' points to a 'char', it will
make it simple to see the pointer arithmetic. We will start pointer 'b' at
address 0 in memory. (Yes, we are not really allowed to touch that area,
but it is easier to show the example without having to calculate offsets.
Why confuse the issue?) Now, I will use this notation:
pointer [offset]
What this means is that 'pointer' is to where in memory it points (the
address) and '[offset]' is a number I add to the pointer to get a new
address with the pointer arithmetic (basically, pointer+offset). Similar to
your example, if I had:
char* b=new char [3];
I would have a base pointer to the array at 'b' (which is where I said
we would start it) and it would be only '3' elements long. Now, consider
your first set of statements where you added the offset and dereferenced. I
will show (in my notation) where memory would actually be addressed after
the result of the calculation. Given that we know 'b' is 0:
*(b) equates to: 0 [0] or address 0
*(b+1) equates to: 0 [1] or address 1
*(b+2) equates to: 0 [2] or address 2
Note that we have 3 addresses above, 0, 1 and 2, which comprise the
relative addresses of the three elements in the array starting from the base
address of 0.
Now, consider the arithmetic in your 'cout' statement:
*(b) equates to: 0 [0] or address 0
At this point, I will note a special case in your other portion of
'cout'. You increment the pointer value, which now changes your base. When
you use "b++", you have now changed 'b' to point at the next element of the
'char' array and its new address is now 1. So now we have:
*(b++) equates to: 1 [0] or address 1
Because you have changed the value of 'b', now you have invalidated your
assumption of a proper offset into the base and the next access to 'b'
becomes:
*(b+2) equates to: 1 [ 2] or address 3
Note, above, we only had access to addresses 0, 1 and 2 as expected.
However, you have now written to addresses 0, 1 and 3 with address '3' being
one element outside of the memory for which you had asked. The debug
allocation libraries write special "magic numbers" in these areas to check
for overwrites of this kind, thus the assertion. In a release build, you
may not notice anything at all, but in all reality you could be trompling
'1' byte of information that may cause a bug quite difficult to duplicate or
catch!
Not only is this a problem, but the 'delete' is a problem as well. Why?
Because instead of deleting 'b' at its original address (in this case 0, but
ignore that in its normal use with the 'delete' operator for purposes of
this example) you are now essentially calling "delete (b+1)" or "delete 1".
In this fashion, double the damage has been done just by what appeared to be
a harmless way to access element 1 of the array through the pointer by
modifying it. When applying this example to other types (i.e. an int* to an
array of type 'int') you can scale the type and pointer arithmetic
accordingly and see that the damage is still pronounced, but on slightly
relatively larger scale with regard to the overwrite. :)
Regards,
Joe
"Thomas Remkus" <Thomas...@hotmail.com> wrote in message
news:ORYH7gmIAHA.270@cppssbbsa05...
> It tells me that I have a "Debug Assertion Failure". It's in dbgheap.c.
Here
> is the exact lines of code:
>
> {
> int* b = new int[3];
>
> *(b) = 12;
> *(b + 1) = 15;
> *(b + 2) = 88;
>
> cout << *(b) << endl << *(b++) << endl << *(b + 2) << endl;
>
> file://TODO: get this to work ... or understand this better.
> file://For some reason this ending statement does not work!!!!!
> cout << *(b) << endl << *(b++) << endl << *(b + 2) << endl;
In addition to what Joe said, the above is undefined, because you're
both modifying b and using it in ways other than to determine its new
value between sequence points. In this sense, the above is equivalent
to:
fun(b, b++, b+2)
The order of evaluation of function arguments is unspecified, and in
practice, you could observe 6 possible orders, 3 of which could affect
the values passed to fun. It depends on when b++ is executed. But
since the code is undefined, for the reason given above, anything at
all could happen.
--
Doug Harrison [VC++ MVP]
Eluent Software, LLC
http://www.eluent.com
Tools for Visual C++ and Windows
fun(fun(fun(NULL,b+2),b++),b);
The order is quite clearly defined there, as the function calls are each
sequence points. (Although if you ask that I quote the standard on that, I
must admit that I will not be able to.)
HOWEVER, the order is clearly NOT what was intended. Or, at least if the
caller had done two ++'s, the results would have been in almost reverse
order.
Let's see, a quick test to see if I'm even vaguely right...
int i=0;
std::cout << i++ << std::endl << i++ << std::endl << i++ << std::endl;
results in:
2
1
0
which (although counter intuitive from reading the code) is in the correct
sequence if you translate it to something like:
fun(fun(fun(NULL,i++),i++)i++);
Or am I way off base here?
--
Reginald Blue | Opinions expressed here do not
Natural Language Understanding | necessarily represent those of
Unisys Corporation | my employer.
--------------------------------+-------------------------------
For speech technology solutions,| r...@NOSPAM.trsvr.tr.unisys.com
NL technology,speech application| My email address is wrong, you
development training, see: | need to remove the obvious.
http://www.speechdepot.com/ +-------------------------------
"Doug Harrison [MVP]" <d...@mvps.org> wrote in message
news:8vhfss81cs8ptm3us...@4ax.com...
>Hmmm...I don't think I agree with you. I must admit that I'm more familiar
>with sequence points wrt C and not C++, however, I'm almost positive that
>this evaluates to something more like:
>
>fun1(fun2(fun3(NULL,b+2),b++),b);
>
>The order is quite clearly defined there, as the function calls are each
>sequence points. (Although if you ask that I quote the standard on that, I
>must admit that I will not be able to.)
There is a sequence point before a function is called, at which point
evaluation of its (and only its) arguments is completed, including
side effects, but the order of evaluation of these arguments is
unspecified. There is no requirement that fun3's arguments be
evaluated before b++, if that's what you mean by "clearly defined
order". In fact, this is a legal evaluation order:
b++
b
NULL
b+2
fun3
fun2
fun1
To see this, consider:
f1(f2(f3(a,b),c),d)
Evaluation of this expression breaks down as follows, where stuff on
the RHS must happen before stuff on the LHS:
f1: f2, d in either order
f2: f3, c in either order
f3: a, b in either order
Or:
f1: f2, d or d, f2
f2: f3, c or c, f3
f3: a, b or b, a
Note that these commas aren't comma operators, and they don't imply
sequence points.
Let's move f3's arguments into f2:
f2: (a, b, f3, c) or (b, a, f3, c) or (c, a, b, f3) or (c, b, a, f3)
or (a, b, c, f3) or (a, c, b, f3)
or (b, a, c, f3) or (b, c, a, f3)
The sequence point for a and b is before the f3 call, while the
sequence point for c is before f2 is called. Thus, the comma preceding
f3 can be thought of as the sequence point for a and b.
The first line follows directly from the fact that argument evaluation
order is unspecified, and the remaining possible orders in the final
two lines follow from the fact that c is unordered with respect to a
and b in terms of sequence points. This frees the compiler to evaluate
c in any order with respect to a and b. If you do this for f1, you'll
get the same sort of result, just longer. Thus, the order I posted at
the beginning of this message is valid.
>HOWEVER, the order is clearly NOT what was intended. Or, at least if the
>caller had done two ++'s, the results would have been in almost reverse
>order.
>
>Let's see, a quick test to see if I'm even vaguely right...
>
> int i=0;
> std::cout << i++ << std::endl << i++ << std::endl << i++ << std::endl;
>
>results in:
>
>2
>1
>0
>
>which (although counter intuitive from reading the code) is in the correct
>sequence if you translate it to something like:
>
>fun1(fun2(fun3(NULL,i++),i++)i++);
>
>Or am I way off base here?
Label the i++ expressions from left to right as a, b, c, replace funN
with operator<< and NULL with cout, ignore the endls, and you will
have translated the infix cout expression into functional form. The
observed evaluation order is:
c, b, a, fun3, fun2, fun1
This nicely illustrates that the order of evaluation of function
arguments is unspecified; you might expect it to be a, b, c, but it
isn't. In addition, the absence of the sequence point between a, b,
and c means that all zeros would be valid output, and the fact that
it's undefined means any result whatsoever is OK.
In general, undefined behavior includes working like you hope it will.
Running code through a compiler and getting some desired result
doesn't establish that the code is well-defined and won't be
interpreted differently by different option settings, future compiler
releases, or other compilers.
I silently watched the events unfold. Unfortunately, I did not
participate in the "definition" of the unknown, I just operated in the realm
of my 'known'. Thank you much Doug for your input in this thread, it is
certainly a learning experience for me every day! :)
Regards,
Joe
"Doug Harrison [MVP]" <d...@mvps.org> wrote in message
news:7cvfss0huidro77tg...@4ax.com...
Should be:
int *pTheNumber = malloc(3*sizeof(int));
Ed
Well, first of all, I'd like to raise a question. Would the statement not
fail in C++, period? From what I understand (and I could very well be wrong
on this) C++ typechecking doesn't allow a void pointer to be assigned to a
typed pointer type. Or, in other words the following syntax:
int *pTheNumber = malloc(3 * sizeof(int));
Should be written as:
int *pTheNumber = (int*)malloc(3 * sizeof(int));
Correct me if I'm wrong on this; but C-style casting is something I feel I
have a pretty good handle on. This is one other thing that new protects
against (above and beyond required the sizeof() operator to be used). It
automatically casts the returned pointer to the appropriate type.
Now... after defending new, I'd like to say that I for one prefer malloc
myself, over the C++ operator where basic data types and structures are
concerned. It's probably doing the exact same thing, either way, but I get
a better idea of what is going on under the hood when I see what I'm casting
to and I see the sizeof() operator being used. It sort of clicks for me
then and there "hey, this is EXACTLY what your getting."
Also, I don't think there is an equivalent to realloc() in C++ is there?
(Beyond the vector class, anyways). If there is, I'd love to hear about it.
Pardon, but 'new' is a C++ keyword and the construct "int* x= new int
[3];" can be usedas was made clear. The 'new' operator has the hidden
effect of dealing with that 'sizeof(type)' operator you mention without its
explicit use that 'C' requires for scaling sizes to fit those types stored
in allocated buffers. Can you offer a reason why that should not be used
and perhaps why your suggestion would be the alternative?
Regards,
Joe
"Edward E. Hopkins" <edwarde...@uswest.net> wrote in message
news:mBVx5.476$JR.4...@news.uswest.net...
Sorry. For some reason Outlook express sent my message before I got
finished typing it all. Anyways...
To put my final two cents in (which is about all I have at this point in the
week) is that personally, even though I use malloc, from a purist point of
view it is better to use the new operator. It does the same thing, only it
does it will less syntax and with automatic pointer typing/scaling.
And there is also the issue of classes to consider. In my understanding,
malloc can be used to allocate memory for a class variable. It will not,
however, call the constructor for said class. Thus, all objects should be
created through use of the 'new' keyword, so that constructors will be
called. If, therefore, your using new for objects you should go ahead and
use it for simple data types and structures as well, or else you'll end up
with two kinds of incompatible memory allocation in your program which could
lead to all sorts of errors when de-allocation occurs.
Just an opinion...
Daemon
(P.S. Offtopic -- Anyone know what shortcut sends messages automatically in
outlook express? I have a habit of messages being sent prematurely when I
press the enter key, when typing, on occasion.)
I believe that you are right...the usefulness of malloc is
that it returns a void * which you must cast into whatever
type is required.
Garett
Yes, the nice part about 'new' is that it will call the constructors for
your objects and does not require the need for an explicit cast. The reason
why there is no concept of 'realloc' in C++ is that shifting objects around
require some type of 'deep' reallocation mechanism for that objects and the
other objects it may contain.
Regards,
Joe
"Dark Daemon" <ren...@mindspring.com> wrote in message
news:8q9hl7$4s4$1...@nntp9.atl.mindspring.net...
Well, I totally agree that fun(b,b++,b+2) will be undefined.
But each of the << is a call to operator<<. (IIRC the OP question,
they are calls to operator<<(int). ) Do they count as sequence points?
I tend to be quite paranoid about sequence points. I try to make
the only one I ever depend on the ; at the end of a statement.
So, even if << did count as a sequence point, I would not write
the line of code in the OP statement.
--
Dan Evens
Standard disclaimers etc. No spam please.
>Well, I totally agree that fun(b,b++,b+2) will be undefined.
>But each of the << is a call to operator<<. (IIRC the OP question,
>they are calls to operator<<(int). ) Do they count as sequence points?
>
>I tend to be quite paranoid about sequence points. I try to make
>the only one I ever depend on the ; at the end of a statement.
>So, even if << did count as a sequence point, I would not write
>the line of code in the OP statement.
Please see my reply to Reginald.
I had to go and ask, but I was mistaken. While it is true that the function
call imposes a sequence point, it only imposes a partial ordering of the
sequencing of events and that a compiler may choose to resolve the sub
expression evaluations in any order it wishes.
My mistake. Sorry.
Hmmm... so what about the following (hard-coded example, I realize):
class CSomething
{
public:
CSomething();
~CSomething();
int dx;
int dy;
}
// Create an array of pointers
CSomething *lpStuff = (CSomething*)malloc(sizeof(CSomething) * 20);
// Set all pointers to null
memset(lpStuff, NULL, sizeof(CSomething * 20));
// Set the objects
for (int i = 0; i < 20; i++)
{
lpStuff[i] = new CSomething();
if (lpStuff[i])
{
lpStuff[i]->dx = i;
lpStuff[i]->dy = -i;
}
}
// Delete the 15th object
if (lpStuff[14])
delete lpStuff[14];
// Shuffle the last pointer into the deleted pointer's position
lpStuff[14] = lpStuff[19];
// Get rid of the last pointer
lpStuff = (CSomething*)realloc(sizeof(CSomething) * 19);
Beyond mixing C and C++ (which I know isn't all to popular, but... well, it
works) you see any problems with using the above example for dynamic
allocation of objects? I know--STL provides simpler support for this
already. But I'm learing and want to know how to do all this low-level
stuff myself, before I rely on the STL.
--
Daemon (a.k.a. Benjamin)
If a fool and his money are so easily parted, why do politicians keep
getting rich?
sizeof(CSomething*)
Definately error prone, I'll admit.
Now toss in virtual functions. I wouldn't want to be playing around
with a vtable. :)
Regards,
Joe
"Dark Daemon" <ren...@mindspring.com> wrote in message
news:8qbnjc$q8t$1...@slb1.atl.mindspring.net...
class buffer
{
char b[1024];
char *p; // iterates through b[]
public:
buffer(char* msg)
{
strcpy(b,msg);
p = b;
}
};
Now, if you move a buffer object, you'll also have to alter the value of p.
--
Truth,
James Curran
http://www.NJTheater.com (Professional)
http://www.NovelTheory.com (Personal)
http://www.BrandsForLess.com (Day Job)
"Joe Delekto" <jdel...@netvillage.com> wrote in message
news:e63lEL4IAHA.277@cppssbbsa04...
Cool. You mean there IS something even nastier than dynamic arrays of
pointers? Haven't had the joy of playing with that yet. I'll have to give
it a go :)
Daemon
Why would you have to move p? In example:
buffer *lpBuffer = new buffer("some text");
The pointer lpBuffer points to an area of memory. You can toss that pointer
around all you want, and put it wherever you want. From what I understand
it doesn't change in anyway the memory pointed to. It might be an issue if
you used a stack-based object (in which I wouldn't even attempt dynamic
allocation) but in the case of an object allocated on the heap, how would
the information within the class be affected by moving the pointer without?
Daemon
Note that he mentioned that "p" was an index into the array b[]. By
reallocating the class and moving it elsewhere, you must move all the
contents of b[] to a new address and appropriately adjust 'p' based on its
position. That's assuming that you even *knew* that 'p' was an index into
b[], but its very difficult for a compiler to guess one's intentions. :)
Regards,
Joe
"Dark Daemon" <ren...@mindspring.com> wrote in message
news:8qebol$fnq$1...@slb6.atl.mindspring.net...
Let's say that after the "buffer *lpBuffer = new buffer("some text");",
the lpBuffer points to address 0x1000. Then lpBuffer->b occupies
0x1000-0x13FF, and the value lpBuffer->p == 0x1000. Now, move the object to
say 0x2000, then lpBuffer->b is now 0x2000-0x23FF, but the value of
lpBuffer->p still == 0x1000.
--
Truth,
James Curran
http://www.NJTheater.com (Professional)
http://www.NovelTheory.com (Personal)
http://www.BrandsForLess.com (Day Job)
James Curran <james...@mvps.org> wrote in message
news:u9#NaxJJAHA.289@cppssbbsa05...
>
> Look carefully at whats going on there....
>
> Let's say that after the "buffer *lpBuffer = new buffer("some
text");",
> the lpBuffer points to address 0x1000. Then lpBuffer->b occupies
> 0x1000-0x13FF, and the value lpBuffer->p == 0x1000. Now, move the object
to
> say 0x2000, then lpBuffer->b is now 0x2000-0x23FF, but the value of
> lpBuffer->p still == 0x1000.
>
>
Ya, but I was pointing out that object memory is not mucked with; only the
pointers that store the location of the object are re-allocated. Given
this, even though the address in memory of the pointer changes, the pointed
to object resides in the same memory space.
Otherwise, how can you move the object? (Using new calls the constructor
for the new object, and malloc/realloc--from my understanding--shouldn't be
used with objects, period). I'd be interesting in hearing how this is done.
Daemon
I disagree. I believe this evaluates to a set of recursive calls to
operator<<. Unfortunately, I'm getting a headache trying to figure
out how it works out. Maybe something like this:
operator<<(cout, operator<<(*(b), operator<<(endl, operator<<(*(b++),
operator<<(endl, operator<<(*(b + 2), endl))))));
Either that way or the other way around.
So instead of fun(b, b++, b+2) you get fun(b, fun(b++, fun(z, b+2)))
as your analogy. I think (and, not being an experienced language
lawyer, I could be mistaken) that regardless of freedom to evaluate
arguments in any order, there is not sufficient freedom to have b++
both before and after b+2.
ISTR this came up on comp.lang.c++.moderated in the context of
a discussion about how introducing classes could alter the legality
of certain arrangements of operation (e.g. (a = b) = c being legal
for classes/structs but not for built-in types), so an appropriate
search on deja could yield some additional viewpoints.
--
Craig Powers
cpo...@lynx.neu.edu
eni...@hal-pc.org
>"Doug Harrison [MVP]" wrote:
>>
>> Thomas Remkus wrote:
>>
>> > cout << *(b) << endl << *(b++) << endl << *(b + 2) << endl;
>>
>> In addition to what Joe said, the above is undefined, because you're
>> both modifying b and using it in ways other than to determine its new
>> value between sequence points. In this sense, the above is equivalent
>> to:
>>
>> fun(b, b++, b+2)
>
>I disagree. I believe this evaluates to a set of recursive calls to
>operator<<. Unfortunately, I'm getting a headache trying to figure
>out how it works out. Maybe something like this:
They're not recursive, they're nested. And please note I'm not saying
that the operator<< expression resolves to the above. I'm only saying
that what it does resolve to is equivalent to the above in terms of
argument evaluation order. I demonstrated that in my reply to
Reginald.
>operator<<(cout, operator<<(*(b), operator<<(endl, operator<<(*(b++),
> operator<<(endl, operator<<(*(b + 2), endl))))));
>
>Either that way or the other way around.
If we call operator<< f, then:
a << b << c << d
is translated into functional form as:
f(f(f(a,b),c),d)
This preserves the left to right associativity of operator<<.
>So instead of fun(b, b++, b+2) you get fun(b, fun(b++, fun(z, b+2)))
>as your analogy. I think (and, not being an experienced language
>lawyer, I could be mistaken) that regardless of freedom to evaluate
>arguments in any order, there is not sufficient freedom to have b++
>both before and after b+2.
But there is. Please see my reply to Reginald, in which I demonstrated
this.
[...]
> But there is. Please see my reply to Reginald, in which I demonstrated
> this.
Hmm. Seems a little counter-intuitive, but despite my best efforts to
find a contradiction (short of reading the standard, which I don't
have) I failed, so I guess I was indeed wrong. My apologies.
>Hmm. Seems a little counter-intuitive, but despite my best efforts to
>find a contradiction (short of reading the standard, which I don't
>have) I failed, so I guess I was indeed wrong. My apologies.
Unfortunately, the standard doesn't give an example. 5.2.2/8 just says
that the evaluation order is unspecified, but knowing that plus a
little about sequence points, it's possible to deduce other facts.