Returning a pointer to a struct

Discussion in 'C++' started by djcredo@gmail.com, Nov 30, 2006.

  1. Guest

    Hey all,

    I want to return a pointer to a struct. Here is what I'lm trying to do:

    struct Position{
    int x;
    int y;
    };

    Position* GraphicTag::getRenderCentre(){
    int cenx = m_renderPosition->x + m_size->width / 2;
    int ceny = m_renderPosition->y + m_size->height / 2;

    return (Position *){cenx,ceny}; // <---- Error here
    }

    I get "Error: initializer for scalar variable requires one element".
    I'm a Java programmer at heart, and still a little uneasy around
    pointers.

    Thanks,
    Matt
     
    , Nov 30, 2006
    #1
    1. Advertising

  2. Guest

    schrieb:
    > I want to return a pointer to a struct. Here is what I'lm trying to do:
    >
    > struct Position{
    > int x;
    > int y;
    > };
    >
    > Position* GraphicTag::getRenderCentre(){
    > int cenx = m_renderPosition->x + m_size->width / 2;
    > int ceny = m_renderPosition->y + m_size->height / 2;
    >
    > return (Position *){cenx,ceny}; // <---- Error here
    > }
    >
    > I get "Error: initializer for scalar variable requires one element".
    > I'm a Java programmer at heart, and still a little uneasy around
    > pointers.


    With a simple data structure like this, it does not make much sense to
    use pointers at all. In C++, I would personally try to return a simple
    structure like this by value or by reference first, and only as a last
    resort would I use pointers.

    You get the error since a pointer in C++ needs (or should) point to
    something. In other words, you need to create a valid object to point
    to first.

    Your structure also has no applicable default constructor that could
    help you here. You should consider adding one.

    And finally, if you have this function create a "Position" object and
    return a pointer to it, the caller will be responsible for deleting the
    object - not necessarily a desired behaiour.

    Alf P. Steinbach (frequent contributor in this group) has a good
    tutorial on C++ pointers:
    http://home.no.net/dubjai/win32cpptut/special/pointers/ch_01.pdf

    Cheers,
    Andre
     
    , Nov 30, 2006
    #2
    1. Advertising

  3. wrote:
    > I want to return a pointer to a struct. Here is what I'lm trying to
    > do:
    >
    > struct Position{
    > int x;
    > int y;
    > };
    >
    > Position* GraphicTag::getRenderCentre(){
    > int cenx = m_renderPosition->x + m_size->width / 2;
    > int ceny = m_renderPosition->y + m_size->height / 2;
    >
    > return (Position *){cenx,ceny}; // <---- Error here
    > }
    >
    > I get "Error: initializer for scalar variable requires one element".
    > I'm a Java programmer at heart, and still a little uneasy around
    > pointers.


    Pointers are good when you have objects addresses of which you can
    take and assign to those pointers. Your "{cenx,ceny}" syntax is not
    C++. If you want to move along in C++, you'll need to un-learn some
    of Java.

    In this particular case do NOT return a pointer. Return an object:

    Position GraphicTag::getRenderCentre(){
    Position retval = { m_renderPosition->x + m_size->width/2,
    m_renderPosition->x + m_size->height/2 };
    return retval;
    }

    Of course, it's better to make your Position to have a c-tor that
    would take two values and construct a temporary right in the
    return expression.

    struct Position{
    int x;
    int y;
    Position(int xx, int yy) : x(xx), y(yy) {}
    };

    ...
    return Position( m_renderPosition..../2, m_render.../2 );
    }

    There are implications about adding your own c-tor to the struct,
    so you decide which path to take.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Nov 30, 2006
    #3
  4. Guest

    Thank you both,

    Firstly, what is the scope of a struct which is created (not as a
    pointer) in a member function? I always thought it was local only
    (would delete when the function is returned), but I'm clearly wrong
    here. Does it last until the object that the member function belongs to
    is destroyed?

    Secondly, am I correct in thinking that there is no "inline" way of
    creating a pointer to a struct like I was trying to, unless I define a
    constructor? (I'm very stubborn, even if it isn't the right way, I like
    to know where I was going wrong with the syntax).

    Thanks again,
    Matt
     
    , Nov 30, 2006
    #4
  5. Gavin Deane Guest

    wrote:
    > Thank you both,
    >
    > Firstly, what is the scope of a struct which is created (not as a
    > pointer) in a member function? I always thought it was local only
    > (would delete when the function is returned), but I'm clearly wrong
    > here. Does it last until the object that the member function belongs to
    > is destroyed?


    The object created within the function has the scope of that function
    and is indeed destroyed [*] at the end of that function. However, when
    you return by value as Victor suggested, a whole new, entirely separate
    object is created for the return value. So by the end of the function,
    the local object has been destroyed, but that doesn't matter because
    the return value is a different object that was created as a copy of
    the local object while the local object still existed.

    [*] Destroyed, not deleted. delete in C++ has a very specific meaning
    (as a keyword, in all lower case). It is what you do to objects with
    dynamic storage duration (those created with new) when you, the
    programmer, decide it is time for them to cease existing.

    Gavin Deane
     
    Gavin Deane, Nov 30, 2006
    #5
  6. wrote:
    > [..]
    > Secondly, am I correct in thinking that there is no "inline" way of
    > creating a pointer to a struct like I was trying to, unless I define a
    > constructor?


    You can use syntax Position() for a default-initialised temporary, if
    it can, the compiler declares and defines the default constructor for
    you. In your case it doesn't make sense, of course.

    > (I'm very stubborn, even if it isn't the right way, I
    > like to know where I was going wrong with the syntax).


    Well, the curly-brace enclosed initialiser list syntax is only used
    (and available) in _declarations_, not in expressions. The 'return'
    statement includes an expression. You can, as you know _declare_
    (and define) your struct as

    Position blah = { 1, 2 };

    Here the "{ 1, 2 }" is the allowed initialiser syntax. You cannot
    do, for example

    foo( { 1, 2} );

    (for some function 'foo' that takes 'Position' as its argument). It
    is not allowed. If you need to create a temporary object and give it
    some non-default value, the class has to define a c-tor, so you
    can use the syntax

    foo( Position(1,2) );

    , for example.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Dec 1, 2006
    #6
  7. Salt_Peter Guest

    wrote:
    > Thank you both,
    >
    > Firstly, what is the scope of a struct which is created (not as a
    > pointer) in a member function? I always thought it was local only
    > (would delete when the function is returned), but I'm clearly wrong
    > here. Does it last until the object that the member function belongs to
    > is destroyed?


    A struct doesn't have a scope - it doesn't exist. An instance of a
    struct does.
    The local variable dies with the function but if you return the
    variable, a copy ctor creates a brand new object in main for you.

    >
    > Secondly, am I correct in thinking that there is no "inline" way of
    > creating a pointer to a struct like I was trying to, unless I define a
    > constructor? (I'm very stubborn, even if it isn't the right way, I like
    > to know where I was going wrong with the syntax).
    >
    > Thanks again,
    > Matt


    Look at it this way. If you *could* use a pointer, you'ld be much
    better off using a const reference instead. Pointers are responsible
    for most of the bugs that programs suffer from. Even in the case of
    allocations, pointers should be replaced by smart_ptr(s) and references
    work nicely with polymorphism.
    A C++ programmer'ss ultimate goal is (or should be) to write an entire
    application without ever directly using a pointer. The resulting code
    will be safer, bug-proof, easily maintainable and effortlessly
    expandable/extendable.

    The solution: a const reference. The only viable alternative is return
    by copy. Are you ready? Cause there is a moral to the story...

    #include <iostream>

    class Position {
    int x, y;
    public:
    Position() : x(0), y(0)
    {
    std::cout << "Position()\n";
    }
    Position(int x_, int y_) : x(x_), y(y_)
    {
    std::cout << "Position(int, int)\n";
    }
    Position(const Position& copy)
    {
    std::cout << "copy Position\n";
    x = copy.x;
    y = copy.y;
    }
    int getx() const { return x; }
    int gety() const { return y; }
    };

    class Graphic
    {
    Position pos; // precious coordinate
    public:
    Graphic() : pos() { }
    void move(const Position& r_pos)
    {
    pos = r_pos;
    }
    const Position& getpos() const // by const ref
    {
    return pos;
    }
    };

    int main()
    {
    Graphic graphic;
    graphic.move( Position(10,10) );
    Position gpos = graphic.getpos();
    std::cout << "pos.x = " << gpos.getx();
    std::cout << "\npos.y = " << gpos.gety();
    std::cout << std::endl;
    }

    /*
    Position() // 0,0
    Position(int, int) // 10,10
    copy Position // the reference is copied safely
    pos.x = 10
    pos.y = 10
    */

    Graphic's getpos() above is a viable candidate for a pointer return
    since its returning an internal member. Thing is: why would i want a
    user of the class to have *access* to my precious graphic's Position?
    Even if it were to be accessed + modified by accident? You could return
    a constant pointer - but then some smart-ass can const_cast<> your
    precious position into oblivion. I'm not joking - i'm dead serious.

    Consider:

    Position* const Graphic::getpos() // by constant pointer
    {
    return &pos;
    }

    some smart ass could write the following side-effect:

    *graphic.getpos() = Position(-1,-1); // modifies your private member
    !!!

    and screw you royally. Try it. Even if getpos() is made const, i can
    *still* modify the internal position with a Postion ptr and a
    const_cast<>.

    Forget doing that with a const reference. Its absolutely nuke-proof.
     
    Salt_Peter, Dec 1, 2006
    #7
  8. Steve Pope Guest

    Salt_Peter <> wrote:

    >A struct doesn't have a scope - it doesn't exist.


    Sure it does. Try compiling the following.

    void foo () {
    {
    struct goo {
    int a;
    };
    goo b; // legal
    }
    goo c; // illegal, causes 'goo undeclared'
    }

    Steve
     
    Steve Pope, Dec 1, 2006
    #8
  9. Salt_Peter Guest

    Steve Pope wrote:
    > Salt_Peter <> wrote:
    >
    > >A struct doesn't have a scope - it doesn't exist.

    >
    > Sure it does. Try compiling the following.
    >
    > void foo () {
    > {
    > struct goo {
    > int a;
    > };
    > goo b; // legal


    dandy, but hardly the context at hand.
    And lets not get confused with an instance's scope, type visibilty and
    type accessibility.
    What you have above is a struct in a closed anonymous namespace.

    namespace GOO {
    struct goo { };
    }

    void foo () {
    GOO::goo b;
    }

    GOO::goo c;

    int main()
    {
    GOO::goo d;
    }
     
    Salt_Peter, Dec 1, 2006
    #9
  10. Steve Pope Guest

    Salt_Peter <> wrote:

    >Steve Pope wrote:


    >> Salt_Peter <> wrote:


    >>> A struct doesn't have a scope - it doesn't exist.
    >>> An instance of a struct does.


    >> Sure it does. Try compiling the following.


    >> void foo () {
    >> {
    >> struct goo {
    >> int a;
    >> };
    >> goo b; // legal


    >dandy, but hardly the context at hand.
    >And lets not get confused with an instance's scope, type visibilty and
    >type accessibility.


    You're right that my point does not address the OP's concern, however
    your statement above seemed to imply that you believe a structure
    declaration (as opposed to the definition of an instance of the
    structure) doesn't have scope. It does, and can be (among perhaps
    other possibilities) either global to a file or local to a block.

    >What you have above is a struct in a closed anonymous namespace.
    >
    >namespace GOO {
    > struct goo { };
    >}
    >
    >void foo () {
    > GOO::goo b;
    >}
    >
    >GOO::goo c;
    >
    >int main()
    >{
    > GOO::goo d;
    >}


    I'm not sure I totally agree that names local to a block are
    identical in behavior to names in an anonymous namespace. For one
    thing, a name can be declared in an anonymous namespace and then used
    outside the namespace's block but within the same file.

    They are somewhat different scoping mechanisms.

    Steve
     
    Steve Pope, Dec 1, 2006
    #10
  11. Guest

    On Dec 1, 12:09 am, wrote:
    > Hey all,
    >
    > I want to return a pointer to a struct. Here is what I'lm trying to do:
    >
    > struct Position{
    > int x;
    > int y;
    >
    > };Position* GraphicTag::getRenderCentre(){
    > int cenx = m_renderPosition->x + m_size->width / 2;
    > int ceny = m_renderPosition->y + m_size->height / 2;
    >
    > return (Position *){cenx,ceny}; // <---- Error here
    >
    > }I get "Error: initializer for scalar variable requires one element".
    > I'm a Java programmer at heart, and still a little uneasy around
    > pointers.


    I'd just like to add, if you haven't figured it out already, that in
    principle there are two instances where you can return a pointer. The
    first is if you have a class/struct with a member, then you can return
    a pointer to that member, but as Salt_Peter has pointed out, this is
    generally not a good idea. The second instance is when you dynamically
    allocate memory for some type, in which case you get a pointer:

    Position* GraphicTag::getRenderCentre(){
    Position* pos = new Position; // OBS!
    pos->x = m_renderPosition->x + m_size->width / 2;
    pos->y = m_renderPosition->y + m_size->height / 2;

    return pos;
    }

    As others have pointed out, this is generally a bad idea, the memory
    allocated by new will not get freed until you call delete on a
    Position-pointer that points to it (like the one returned from
    getRenderCentre()), should you loose this pointer you have a
    memory-leek. In general, every new shall have a delete, the problem is
    that you only call new in one place but you often might need to delete
    in several places. This leads to two problems, either you don't delete
    where you should, and you get a memory-leek, or you try to use a
    pointer that has already deleted, in which case (if you are lucky) the
    program will crash (if you are unlucky anything could happen).

    --
    Erik Wikström
     
    , Dec 1, 2006
    #11
  12. Steve Pope Guest

    <> wrote:

    >I'd just like to add, if you haven't figured it out already, that in
    >principle there are two instances where you can return a pointer. The
    >first is if you have a class/struct with a member, then you can return
    >a pointer to that member, but as Salt_Peter has pointed out, this is
    >generally not a good idea. The second instance is when you dynamically
    >allocate memory for some type, in which case you get a pointer:


    Actually, there's a third situation when you can return a pointer:
    it can point to a static or global object. That's in a sense
    the safest type of pointer to return.

    Steve
     
    Steve Pope, Dec 1, 2006
    #12
  13. Guest

    Wow, this has been a very enlightening thread, thank you all who have
    made time to post and write code examples!

    Every new user should read this thread - many C++ books / tuts tell you
    how to "code", but don't tell you how to "build software" if you know
    what I mean. Rules like this should be committed to memory.

    I have one final question if you would:

    I have a class GraphicTag which has a member of type Tag (a class, not
    struct). Both the Tag and GraphicTag objects are created in the main()
    function, then the Tag is passed to the GraphicTag constructor:

    int main(){

    Tag tag(10,5);
    GraphicTag gTag(// pass tag here to constructor);

    }

    My question is, how is it best to store the Tag inside the GraphicTag,
    and hence, how is it best to pass it in the constructor? The Tag object
    won't be changed inside the main() function; once it's passed to the
    GraphicTag, it is left alone from the main() function's point of view.
    Is it possible to do this:

    int main(){
    Tag* tag = new Tag(10,5);
    GraphicTag gTag(tag);
    }

    class GraphicTag {
    protected:
    Tag m_tag;
    };

    GraphicTag::GraphicTag(Tag* tag){
    m_tag = *tag; // m_tag is now the instance of the
    created tag.
    }

    .... and is this even the best way?

    Thanks again,
    Matt
     
    , Dec 1, 2006
    #13
  14. Guest

    On Dec 1, 11:13 am, wrote:
    > Wow, this has been a very enlightening thread, thank you all who have
    > made time to post and write code examples!
    >
    > Every new user should read this thread - many C++ books / tuts tell you
    > how to "code", but don't tell you how to "build software" if you know
    > what I mean. Rules like this should be committed to memory.
    >
    > I have one final question if you would:
    >
    > I have a class GraphicTag which has a member of type Tag (a class, not
    > struct). Both the Tag and GraphicTag objects are created in the main()
    > function, then the Tag is passed to the GraphicTag constructor:
    >
    > int main(){
    >
    > Tag tag(10,5);
    > GraphicTag gTag(// pass tag here to constructor);
    >
    > }My question is, how is it best to store the Tag inside the GraphicTag,
    > and hence, how is it best to pass it in the constructor? The Tag object
    > won't be changed inside the main() function; once it's passed to the
    > GraphicTag, it is left alone from the main() function's point of view.
    > Is it possible to do this:
    >
    > int main(){
    > Tag* tag = new Tag(10,5);
    > GraphicTag gTag(tag);
    >
    > }class GraphicTag {
    > protected:
    > Tag m_tag;
    >
    > };GraphicTag::GraphicTag(Tag* tag){
    > m_tag = *tag; // m_tag is now the instance of the
    > created tag.
    >
    > }... and is this even the best way?


    You could, but once again, a pointer is not the best way to do it.
    There are two "problems" with this approach, first you use dynamic
    allocated memory (new) when you don't have to, the second is that if
    the tag created in main() won't change, you don't have to store a copy
    of it in GraphicTag, you can store the thing itself (or rather a
    reference to it).

    class GraphicTag {
    protected:
    Tag& m_tag; // notice the &, a reference
    };

    GraphicTag::GraphicTag(Tag& tag){
    m_tag = tag; // m_tag is now a reference to the tag
    created in main
    }

    int main(){
    Tag tag(10,5);
    GraphicTag gTag(tag);
    }

    Read up on references, they can often be used where a pointer can be
    used, and in those cases a reference is almost always preferable. A
    note on style: try to keep at least the closing '}' on a separate line,
    it will make the code easier to read.

    --
    Erik Wikström
     
    , Dec 1, 2006
    #14
  15. Guest

    On Dec 1, 11:39 am, ""
    <> wrote:
    A
    > note on style: try to keep at least the closing '}' on a separate line,
    > it will make the code easier to read.


    Disregard that, seems it's only google messing up the code.

    --
    Erik Wikström
     
    , Dec 1, 2006
    #15
  16. Guest

    Thank you, I am now much more clued-in about pointers and references. I
    am very greatful! I will aim to use references much more now (I had
    completely overlooked them and just jumped into pointers)!

    Thanks again,
    Matt
     
    , Dec 1, 2006
    #16
  17. Gavin Deane Guest

    wrote:
    > I have a class GraphicTag which has a member of type Tag (a class, not
    > struct). Both the Tag and GraphicTag objects are created in the main()
    > function, then the Tag is passed to the GraphicTag constructor:
    >
    > int main(){
    >
    > Tag tag(10,5);
    > GraphicTag gTag(// pass tag here to constructor);
    >
    > }
    >
    > My question is, how is it best to store the Tag inside the GraphicTag,
    > and hence, how is it best to pass it in the constructor? The Tag object
    > won't be changed inside the main() function; once it's passed to the
    > GraphicTag, it is left alone from the main() function's point of view.


    What do you mean by "it is left alone from the main() function's point
    of view"? Do you mean main does not touch the Tag object, does not
    change it, does not pass it to any other functions or objects, does not
    care in any way about it after the GraphicTag is created? If so, then
    the Tag is logically owned by the GraphicTag and should not even exist
    in main.

    class Tag
    {
    public:
    Tag(int a, int b) {}
    // ...
    };

    class GraphicTag
    {
    public:
    GraphicTag(int tag_param_1, int tag_param_2) :
    tag(tag_param_1, tag_param_2) {}
    // ...
    private:
    Tag tag;
    // ...
    };

    int main()
    {
    GraphicTag gTag(10, 5);
    }

    Gavin Deane
     
    Gavin Deane, Dec 1, 2006
    #17
  18. Gavin Deane Guest

    wrote:
    > Read up on references, they can often be used where a pointer can be
    > used, and in those cases a reference is almost always preferable.


    As long as that doesn't contradict the ownership semantics of the
    design. I saw nothing in the original question to suggest that the
    simplest solution, holding a member object rather than holding a
    reference or pointer, was inappropriate.

    Gavin Deane
     
    Gavin Deane, Dec 1, 2006
    #18
    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. Chris Fogelklou
    Replies:
    36
    Views:
    1,410
    Chris Fogelklou
    Apr 20, 2004
  2. beetle
    Replies:
    2
    Views:
    932
    beetle
    Jan 25, 2005
  3. Zero
    Replies:
    16
    Views:
    670
    Barry Schwarz
    Nov 19, 2005
  4. Spiffy
    Replies:
    3
    Views:
    1,127
    Pascal J. Bourguignon
    Sep 21, 2009
  5. aleksa

    Struct pointer vs. struct array pointer

    aleksa, Feb 20, 2013, in forum: C Programming
    Replies:
    16
    Views:
    487
    Shao Miller
    Feb 20, 2013
Loading...

Share This Page