CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11
  1. #1
    Join Date
    Dec 2003
    Posts
    30

    vector->push_back - confusion about pointer syntax

    Hi again!

    I`ve puzzled the next one rather long, and I´m pretty stuck with it:

    Code:
    void loadAnimals(const vector<Animal*> *animals, const char* filename)
    {
      ...
      ...
      // open file, etc.
      ...
      Animal *animal = NULL;
      // bunch of code to read animal data from the file.
      // the animal`s type (inheritance) is determined here
      // this part works fine.
      // for example,     animal = new Dog();
    
      // puzzled about this
      animals->push_back(*animal);  // won`t compile
      // animals->push_back(&animal);  // won`t compile
    }

    how do I push the object into the vector?

  2. #2
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    & is the address of operator, which will give you Animal**. * is the dereference operator, which will give you Animal.

    Since you already have Animal*, you merely need to do this:

    Code:
       animals->push_back(animal);
    Jeff

  3. #3
    Join Date
    Dec 2003
    Posts
    30
    well, it worked and it didn`t

    First I did as you suggested. But the compiler complained
    -> I removed the word const from the function declaration
    and it worked.

    Doesn`t the const mean that the given reference *animals cannot be changed, but the contents of the vector can?

    Isn`t that a perfomance hit if I leave the const out ?!


    Many many thank a-gain!

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449
    Originally posted by halmark6Z
    well, it worked and it didn`t

    First I did as you suggested. But the compiler complained
    -> I removed the word const from the function declaration
    and it worked.

    Doesn`t the const mean that the given reference *animals cannot be changed, but the contents of the vector can?

    Isn`t that a perfomance hit if I leave the const out ?!


    Many many thank a-gain!
    Pass the vector by reference.
    Code:
    void loadAnimals(vector<Animal*>& animals, const char* filename)
    {
      Animal *animal = NULL;
      animals.push_back(animal);  // won`t compile
      // animals->push_back(&animal);  // won`t compile
    }
    Since you are calling a non-const vector function (push_back), the vector must not be const. When you pass a reference, you are not creating a temporary, so there is no performance hit.

    Regards,

    Paul McKenzie

  5. #5
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    In addition you might want to take a look at this introduction.

  6. #6
    Join Date
    Dec 2003
    Posts
    30
    thanks for your help!

    Though, now the compiler says:

    Code:
    FileUtils.cpp: In member function `void FileUtils::loadAnimals(const std::vector<Animal*, std::allocator<Animal*> >&, const char*)':
    FileUtils.cpp:91: passing `const std::vector<Animal*, std::allocator<Animal*> >' 
    as `this' argument of 
    `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = Animal*, _Alloc = std::allocator<Animal*>]' discards qualifiers
    about this line:

    Code:
    Animal *animal;
    ...
    ...
    animal = new Dog();
    ...
    animals.push_back(animal);  <- this line

  7. #7
    Join Date
    Apr 1999
    Location
    Altrincham, England
    Posts
    4,470
    You're still declaring the function argument as reference to const.
    Correct is better than fast. Simple is better than complex. Clear is better than cute. Safe is better than insecure.
    --
    Sutter and Alexandrescu, C++ Coding Standards

    Programs must be written for people to read, and only incidentally for machines to execute.

    --
    Harold Abelson and Gerald Jay Sussman

    The cheapest, fastest and most reliable components of a computer system are those that aren't there.
    -- Gordon Bell


  8. #8
    Join Date
    Dec 2003
    Posts
    30
    Thanks! Got it working.

    Now it got intresting, I tried
    to run a small Test program.

    Code:
    class House
    {
    private:
      vector<Animals*> *animals;
    
    House::House(const string &housename, const vector<Animal*> &anims)
    {
      ...
      *animals	= anims; // compiles 
    }
    };
    The assignment: *animals = anims compiles
    but causes a runtime exception
    Code:
    Exiting due to signal SIGSEGV
    General Protection Fault at eip=0001b2e0
    I guess the assignment is invalid ?!

  9. #9
    Join Date
    Mar 2002
    Location
    California
    Posts
    1,582
    "animals" should be declared as a regular object and not a pointer:

    Code:
    class House
    {
    private:
      vector<Animals*> animals;
    House::House(const string &housename, const vector<Animal*> &anims)
    {
      ...
      animals = anims; // compiles 
    }
    };
    Either that or you must allocate your pointer with "new". Either that or if your intent is to really have a pointer to the passed in array, you could do "animals = &animals;" if your animals pointer is also declared as const.

    There are tons of tutorials, books and faqs that will set you straight on pointers and all these other basics that you're having trouble with. Asking questions like this is a horrible way to learn C++, and will take much much longer. The reason is you are only asking questions when you run into a problem. There are more important things that you don't even know HOW to ask.

    For instance, in your example above, you now have two vectors pointing at the same allocated memory. Who owns that memory? Who is responsible for deleting it? There's a very elegant solution involving smart pointers to handle the memory for you, but I won't even suggest it before you get a better handle on the basics.

    Get a book. It'll save you time and headaches in the long run.

    Jeff

  10. #10
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,721
    Well, jfaust already answered this, but since I wrote something up ...

    Let's look at a simpler case ...

    Code:
    int i = 10;
    int* pi;
    pi = &i;  // points pi to a valid int
    so "i" is an int and "pi" is a pointer to int. Currently, pi points to "i".

    Code:
    *pi = 2;
    changes the int variable pointed to by pi to 2 ("i" in this case).

    Now look at this :

    Code:
    int* pi;
    *pi = 2;  // dereferences the pointer
    pi does not point to a valid int variable, so deferencing the pointer
    is undefined (basically means you don't know what will happen).

    This is basically what you are doing ...

    Code:
    vector<Animal*> *animals;
    *animals = anims;
    animals is a pointer to a vector<Animal*>, but it doesn't point to anything.
    *animals dereferences the pointer.

    There are many ways to fix this depending on what you want to do (for instance,
    is House going to be able to modify the animals vector ?). Here are a few. Note:
    in the House constructor, I set the animals variable in the initialization
    list instead of the body of the constructor. Its usually a good idea to do
    that when you can (and sometimes you must do that).

    • one way
      Code:
      class House
      {
      public:
      
          House(const string &housename, vector<Animal*> &anims);   // remove the const
      
      private:
      
          vector<Animal*> *animals;  // no const here
      };
      
      House::House(const string &housename, vector<Animal*> &anims) // no const
          :animals (&anims)    // point the animals pointer to a valid vector<Animal*>
      {
      }
    • another (basically the same , just a const difference)
      Code:
      class House
      {
      public:
      
          House(const string &housename, const vector<Animal*> &anims);   // keep the const
      
      private:
      
          const vector<Animal*> *animals;  // add const here
      };
      
      House::House(const string &housename, const vector<Animal*> &anims) // keep the const
          :animals (&anims)    // point the animals pointer to a valid vector<Animal*>
      {
      }
    • making the variable a vector instead of a pointer
      Code:
      class House
      {
      public:
      
          House(const string &housename, const vector<Animal*> &anims);
      
      private:
      
          const vector<Animal*> animals;  // an actual vector, not a pointer (const is optional)
      };
      
      House::House(const string &housename, const vector<Animal*> &anims)
          :animals (anims)  // copy the entire vector
      {
      }


    Also note, in the code above that kept animals as a pointer, I
    just set the pointer (no new as mentioned by jfaust). In this
    case, the vector that was passed to the House constructor
    must remain valid as long as the House variable is valid.

  11. #11
    Join Date
    Oct 2000
    Location
    London, England
    Posts
    4,773
    You look like you are going to run into more problems, as you have a vector of pointers, and you are going to copy this into another vector of the same pointers.

    Which vector is going to delete the pointers?

    Memory management is a complex problem, which is why many new languages (Java and C#) have taken it out of the equation now and handle it for you. So in Java you have to call new but you don't have to call delete.

    Another issue, having handled all that, is that you will have a vector of pointers to class "animal" which is a base class, and you will be having pointers to derived classes, so you need to ensure that class animal has a virtual destructor.

    The best option is to use reference-counting. I have my own set of smart-pointers which are freely available at
    http://www.nmtop40.com/CodeBase/SmartPtrT.h

    Even then you have to know which ones to use when.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured