struct question

Discussion in 'C++' started by Eric, Oct 19, 2006.

  1. Eric

    Eric Guest

    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
    Eric, Oct 19, 2006
    #1
    1. Advertising

  2. Eric

    Eric Guest

    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
    Eric, Oct 19, 2006
    #2
    1. Advertising

  3. Eric

    Noah Roberts Guest

    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.
    Noah Roberts, Oct 19, 2006
    #3
  4. Eric

    Alan Johnson Guest

    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
    Alan Johnson, Oct 19, 2006
    #4
  5. Eric

    Salt_Peter Guest

    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.
    Salt_Peter, Oct 19, 2006
    #5
  6. Eric

    Eric Guest

    Re: struct questio

    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.
    Eric, Oct 19, 2006
    #6
  7. Eric

    Salt_Peter Guest

    Re: struct questio

    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.
    Salt_Peter, Oct 19, 2006
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. RA Scheltema
    Replies:
    3
    Views:
    380
    RA Scheltema
    Jan 6, 2004
  2. Gunnar G

    struct in struct

    Gunnar G, May 31, 2004, in forum: C++
    Replies:
    14
    Views:
    784
  3. DanielEKFA
    Replies:
    8
    Views:
    585
    DanielEKFA
    May 16, 2005
  4. James Harris
    Replies:
    4
    Views:
    1,355
    James Harris
    Oct 9, 2003
  5. Chris Fogelklou
    Replies:
    36
    Views:
    1,345
    Chris Fogelklou
    Apr 20, 2004
Loading...

Share This Page