C ++ vector without pointers

I have std::vector<Enemy*> enemies

, and when I create a new one Enemy

, I do enemies.push_back(this)

. This works for what I am doing, but I am wondering if there is a way so that the vector does not need opponents pointers. I've only tried it std::vector<Enemy>

, but it seems to be causing a lot of problems that I can't figure out.

so - had to change to enemies.push_back(*this)

, and for some reason it caused some linker errors.

perform a loop with the following works, but deleting pointers creates problems:

void Enemy::updateEnemies(sf::RenderWindow &window) {
    for(std::vector<Enemy*>::iterator it = enemies.begin(); it < enemies.end(); it++) {
        (*it)->update(window);
    }
}

      

I wonder if anyone can point me in the direction of using a vector without pointers and loop through it by updating the objects inside it with the same function.

+3


source to share


4 answers


everbody says it in the comments, but his answer is

use smart pointers

if you don't know how to do it then google



Life is much easier, safer, faster, ...

And they are very easy to use - the main trick with using them is to trust them and not try to get smart or "help" them.

+2


source


My practice is to make sure the class implements (and does public

) all of the following: default constructor, copy constructor, assignment operator, and destructor. Then there is no problem with things like std::vector<Enemy>

. (The default constructor isn't even needed for vectors, but can be useful for other things.)

One caveat: if you push_back()

a Enemy

into your vector, this is actually a copy of the original instance that is stored. This causes several errors: firstly, changes to the original (such as variable element data e

in the scope of main()

my example below) will not affect the copy stored in the vector. If you are used to working with pointers, this can be surprising. Second, implicitly building copies and copying member data will take time, which may or may not have a significant performance impact. Third, implicit construction and copying can cause side effects (you should just avoid them in your design where possible).



Here's an example:

#include <vector>
#include <iostream>

class Enemy
{
  public:
    Enemy() : mEvilness( 1 ) {}    // default (i.e. parameterless) constructor
    Enemy( const Enemy& other ) { Copy( other ); } // copy constructor
    Enemy& operator=( const Enemy& other ) { return Copy( other ); } // assignment operator
    ~Enemy() {}  // destructor

    Enemy( int evilness ) : mEvilness( evilness ) {}  // standard constructor

    void Gloat( void ) const
    {
        std::cout << "muahaha";
        for( int i = 0; i < mEvilness; i++ ) std::cout << "ha";
        std::cout << "!\n";
    }

    int mEvilness;

  private:

    // common helper method for copy constructor and assignment operator:
    Enemy& Copy( const Enemy& other )
    {
        mEvilness = other.mEvilness; // make copies of any other member data here
        return *this;
    } 
};


typedef std::vector< Enemy > EnemyHorde;

void AllGloat1( const EnemyHorde& h ) // doesn't matter if you pass by reference...
{
    for( EnemyHorde::const_iterator it = h.begin(); it != h.end(); it++ )
        it->Gloat();
}

void AllGloat2( EnemyHorde h ) // ...or value (but this will take more CPU time)
{
    for( EnemyHorde::const_iterator it = h.begin(); it != h.end(); it++ )
        it->Gloat();
}

int main( int argc, const char* argv[] )
{
    EnemyHorde h;
    Enemy e( 1 );
    h.push_back( e );
    h.push_back( Enemy( 2 ) ); // even transient Enemy instances get copied and stored
    h.push_back( Enemy( 3 ) );

    AllGloat1( h );
    std::cout << "\n";

    e.mEvilness++;  // this will have no effect on the output because h contains a *copy* of e

    AllGloat2( h );

    return 0;
}

      

+1


source


If you want an informed answer, you need to take one step back - to design. As far as I can see, Enemy objects are registered via the constructor as a global list. So far so good.

But how is this object produced? In this example in Enemy you can build everywhere

  • On the stack as local
  • With the new (smartpointer)
  • As an element in a vector, list, deque ...
  • ...

Depending on this, the Enemy-object cannot make any reliable statements about its storage. But one thing that all objects share and that is always accessible from within the object is the address ('this'). Thus, the pointer solution is the only solution that is universal across all Enemy objects. (References in this context are also "sort of a pointer", and other more complex constructs can rely on pointers as well).

A std :: vector Doesn't work because you are getting 2 different objects. Changing one of them does not affect the other. It won't work. And it's impossible to switch to smart pointers without changing the design.

There are 2 general solutions:

Managing the listing from 'inside' Enemy in a general way, as in this example. Extensible with more features such as auto delete entries via destructor .....

Listing management from "outside". No enemy objects are registered, the enemy object generator is responsible for executing correctly (the factory design pattern is a good solution in this case). And you can use smart pointers, which is a good idea in most cases.

There are a few more solutions (including some good solutions) that don't matter, they go beyond the scope of the question.

+1


source


You don't need pointers (most of the time) in C ++.

A copy will be made when using the method std::vector::push_back()

.

Example:

Enemy evil_wizard;
std::vector<Enemy> enemy_container;
enemy_container.push_back(evil_wizard);
Enemy Evil_knight;
enemy_container.push_back(Evil_knight);
Enemy pink_elephant;
enemy_container.push_back(pink_elephant);

      

0


source







All Articles