Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > struct question

Reply
Thread Tools

struct question

 
 
Eric
Guest
Posts: n/a
 
      10-18-2006
This IS material from a CS class on object oriented programming. It is
NOT my homework.

Consider the following:

struct A {short i; void f () {cout << "A::f()\n";}};
struct B : A {long j; void f () {cout << "B::f()\n";}
void g () {cout << "B::g()\n";}};
{
A* const a = new B[10]; // dangerous (1)
a[0].f(); // A::f();
// a[1].f(); // undefined (2)
// delete [] a; // undefined (3)
}

I have questions about three lines, which are marked.

(1): Why might this be considered dangerous?
(2): This line is commented out and marked as undefined. And yet, when I
remove the comment, it compiles and runs, producing the same output as
a[0].f(), that is, A::f(). Why is this?
(3): Again, though this is marked as undefined, when I uncomment it, it
executes fine.

I haven't been able to introduce complications. Why then, might these
lined be marked as such?

Thanks,
Eric
 
Reply With Quote
 
 
 
 
Eric
Guest
Posts: n/a
 
      10-18-2006
Here is the same code from the program, ready to be copy/pasted and
compiled:

#include <iostream>
using namespace std;

struct A {short i; void f () {cout << "A::f()\n";}};
struct B : A {long j; void f () {cout << "B::f()\n";}
void g () {cout << "B::g()\n";}};
int main () {
A* const a = new B[10]; // dangerous (1)
a[0].f(); // A::f();
// a[1].f(); // undefined (2)
// delete [] a; // undefined (3)
return 0;
}

Eric wrote:
> This IS material from a CS class on object oriented programming. It is
> NOT my homework.
>
> Consider the following:
>
> struct A {short i; void f () {cout << "A::f()\n";}};
> struct B : A {long j; void f () {cout << "B::f()\n";}
> void g () {cout << "B::g()\n";}};
> {
> A* const a = new B[10]; // dangerous (1)
> a[0].f(); // A::f();
> // a[1].f(); // undefined (2)
> // delete [] a; // undefined (3)
> }
>
> I have questions about three lines, which are marked.
>
> (1): Why might this be considered dangerous?
> (2): This line is commented out and marked as undefined. And yet, when I
> remove the comment, it compiles and runs, producing the same output as
> a[0].f(), that is, A::f(). Why is this?
> (3): Again, though this is marked as undefined, when I uncomment it, it
> executes fine.
>
> I haven't been able to introduce complications. Why then, might these
> lined be marked as such?
>
> Thanks,
> Eric

 
Reply With Quote
 
 
 
 
Noah Roberts
Guest
Posts: n/a
 
      10-18-2006

Eric wrote:
> This IS material from a CS class on object oriented programming. It is
> NOT my homework.
>
> Consider the following:
>
> struct A {short i; void f () {cout << "A::f()\n";}};
> struct B : A {long j; void f () {cout << "B::f()\n";}
> void g () {cout << "B::g()\n";}};
> {
> A* const a = new B[10]; // dangerous (1)
> a[0].f(); // A::f();
> // a[1].f(); // undefined (2)
> // delete [] a; // undefined (3)
> }
>
> I have questions about three lines, which are marked.
>
> (1): Why might this be considered dangerous?
> (2): This line is commented out and marked as undefined. And yet, when I
> remove the comment, it compiles and runs, producing the same output as
> a[0].f(), that is, A::f(). Why is this?
> (3): Again, though this is marked as undefined, when I uncomment it, it
> executes fine.
>
> I haven't been able to introduce complications. Why then, might these
> lined be marked as such?


prob 1: Your objects are not polymorphic but you treat them as such.
prob 2: You're attempting to store objects polymorphically in an array.

I'll leave it to you to see how those two problems answer your three
questions.

 
Reply With Quote
 
Alan Johnson
Guest
Posts: n/a
 
      10-19-2006

Eric wrote:
> This IS material from a CS class on object oriented programming. It is
> NOT my homework.
>
> Consider the following:
>
> struct A {short i; void f () {cout << "A::f()\n";}};
> struct B : A {long j; void f () {cout << "B::f()\n";}
> void g () {cout << "B::g()\n";}};
> {
> A* const a = new B[10]; // dangerous (1)
> a[0].f(); // A::f();
> // a[1].f(); // undefined (2)
> // delete [] a; // undefined (3)
> }
>
> I have questions about three lines, which are marked.
>
> (1): Why might this be considered dangerous?
> (2): This line is commented out and marked as undefined. And yet, when I
> remove the comment, it compiles and runs, producing the same output as
> a[0].f(), that is, A::f(). Why is this?
> (3): Again, though this is marked as undefined, when I uncomment it, it
> executes fine.
>
> I haven't been able to introduce complications. Why then, might these
> lined be marked as such?
>
> Thanks,
> Eric


Let's make some assumptions about your platform. Whether these are true
for your specific platform isn't really relevant:
1) A "short" is 2 bytes.
2) A "long" is 4 bytes.
3) There are no padding bytes added in struct A or struct B.

Consider what gets created in memory (with the above assumptions) when
"new B[10]" is executed. If we represent each byte with the name of
the variable it is a part of, and separate each object by a '|', it
looks something like:

iijjjj | iijjjj | iijjjj | iijjjj | iijjjj | iijjjj | iijjjj | iijjjj |
iijjjj | iijjjj

Now, as I'm sure you know, when 'a' is a pointer, a[x] is essentially
just shorthand for *(a+x). Under our assumptions above, sizeof(struct
A) is 2. So, given that knowledge, try to identify which object is
identified by a[1] in our crude picture of memory.

This should be enough for you to be able to answer your questions.

--
Alan Johnson

 
Reply With Quote
 
Salt_Peter
Guest
Posts: n/a
 
      10-19-2006

Eric wrote:
> This IS material from a CS class on object oriented programming. It is
> NOT my homework.
>
> Consider the following:
>
> struct A {short i; void f () {cout << "A::f()\n";}};
> struct B : A {long j; void f () {cout << "B::f()\n";}
> void g () {cout << "B::g()\n";}};
> {
> A* const a = new B[10]; // dangerous (1)
> a[0].f(); // A::f();
> // a[1].f(); // undefined (2)
> // delete [] a; // undefined (3)
> }
>
> I have questions about three lines, which are marked.
>
> (1): Why might this be considered dangerous?
> (2): This line is commented out and marked as undefined. And yet, when I
> remove the comment, it compiles and runs, producing the same output as
> a[0].f(), that is, A::f(). Why is this?
> (3): Again, though this is marked as undefined, when I uncomment it, it
> executes fine.
>
> I haven't been able to introduce complications. Why then, might these
> lined be marked as such?
>
> Thanks,
> Eric


They are marked as such because they are wrong.

(1) is wrong because you are allocating a non-polymorphicly derived
type (x10) and storing that array's address in a pointer to Base A
(which, incidently, thinks that you stored 10 bases). Imagine the mess.
Its not just dangerous - its destructive.

your array, logicly looks like this (where each letter is the
corresponding memory allocated):

ABABABABABABABABABAB

and your pointers is absolutely convinced that it has:

AAAAAAAAAA

a[0].f() happens to work by pure luck since its the first that was
allocated in that fake pointer's index.
(2) is wrong in the sense that B:f() is expected but polymorphism has
been denied by the coder. The result of that statement is undefined.
And it IS undefined because the pointer is unaware that the array is
actually an array of B's. If you had attempted to access a member
variable with A::f(), the program would have crashed on the spot.
Obviously,the second element of base A is not were the pointer thinks
it is.

(3) is nasty because because that dumb pointer proceeds to calculate
the size of base A, multiplies it by 10 and attempts to deallocate only
a portion of the aforementioned array allocation. And thats twice as
nasty because each time the destructor for A is invoked (except the
first), its invoked on something that is not an A or for that matter
anything at all (so the member short i is never released). Not to
mention that the destructors of B were not even attempted. You just
leaked into memory the entire allocation except one instance of base A.

Why don't you declare and define you ctors and d~tors with std::cout
outputs? Deallocation is a requirement and absolutely critical in this
language.

 
Reply With Quote
 
Eric
Guest
Posts: n/a
 
      10-19-2006
Thank you for your reply. What I know and a little reading on
polymorphism helped me understand this much better.

> Why don't you declare and define you ctors and d~tors with std::cout
> outputs? Deallocation is a requirement and absolutely critical in this
> language.
>


I'm not sure I understand where cout fits into this.
 
Reply With Quote
 
Salt_Peter
Guest
Posts: n/a
 
      10-19-2006
Eric wrote:
> Thank you for your reply. What I know and a little reading on
> polymorphism helped me understand this much better.
>
> > Why don't you declare and define you ctors and d~tors with std::cout
> > outputs? Deallocation is a requirement and absolutely critical in this
> > language.
> >

>
> I'm not sure I understand where cout fits into this.


Constructors and destructors are pivotal in this language, the compiler
has no choice but to generate them if you don't anyways. Specially when
using polymorphism and developing new theories, give the compiler a
chance to give you feedback about whats happening. Also, instead of
creating a container of one million objects, get one object to work
correctly first.

#include <iostream>
#include <memory>

struct A
{
A() : i(0) { std::cerr << "A()\n"; } // def ctor
virtual ~A() { std::cerr << "~A()\n"; } // d~tor, polymorphic
/* member functions */
virtual void f() const // virtual member function
{
std::cerr << "A::f()\n";
std::cout << "i = " << i;
std::cout << std::endl;
}
private:
short i;
};

struct B : public A
{
B() : j(0) { std::cerr << "B()\n"; }
~B() { std::cerr << "~B()\n"; } // automatically virtual
void f() const // automatically virtual
{
std::cerr << "B::f()\n";
std::cout << "j = " << j;
std::cout << std::endl;
}
private:
long j;
};

int main()
{
std::auto_ptr< A > p_a( new B() ); // same as new/delete except its
automatic
p_a->f();

return 0;
}

/* output if A is polymorphic
A()
B()
B::f()
j = 0
~B() // std::auto_ptr goes out of scope, invokes d~tors polymorphicly
~A()
*/

/* without virtuals
A()
B()
A::f() // wrong function called !!!
i = 0
~A()
// mem leak, B() is never destroyed
*/

You'll understand that the result of removing the virtual keywords is
much more dangerous than you think in your program. Its incorrect *and*
catastrophic.
Without polymorphism, imagine what happens if A::f() attempts to access
short i in the second element, which is not of type A, if you had an
array?
The consequences are dramatic.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Can *common* struct-members of 2 different struct-types, that are thesame for the first common members, be accessed via pointer cast to either struct-type? John Reye C Programming 28 05-08-2012 12:24 AM
Typedef A references struct B which references struct A which... DanielEKFA C++ 8 05-16-2005 10:26 AM
struct in struct Gunnar G C++ 14 06-02-2004 06:43 PM
struct my_struct *p = (struct my_struct *)malloc(sizeof(struct my_struct)); Chris Fogelklou C Programming 36 04-20-2004 08:27 AM
implementing a templated struct within a templated struct RA Scheltema C++ 3 01-06-2004 11:25 AM



Advertisments