簡體   English   中英

沒有指針的c ++向量

[英]c++ vector without pointers

我有一個std::vector<Enemy*> enemies ,當我創建一個新的Enemy我會做enemies.push_back(this) 這適用於我正在做的事情,但我想知道是否有辦法讓矢量不需要指向敵人的指針。 我試過std::vector<Enemy>但它似乎引起了一堆我無法弄清楚的問題。

即。 - 不得不改為enemies.push_back(*this) ,並且由於某種原因導致了一些鏈接器錯誤。

循環使用以下工作,但刪除指針會產生問題:

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

想知道是否有人可以指向我使用沒有指針的向量並循環通過它的方向,用相同的函數更新其中的對象。

有人在評論中這么說 - 但答案是肯定的

使用智能指針

如果你不知道怎么做那么谷歌

你的生活更輕松,更安全,更快......

而且它們真的很容易使用 - 使用它們的主要技巧是信任它們而不是試圖變得聰明或“幫助”它們

我的做法是確保該類實現(並public )以下所有內容:默認構造函數,復制構造函數,賦值運算符和析構函數。 那么像std::vector<Enemy>這樣的東西也沒問題。 (對於向量,默認構造函數甚至不是必需的,但對於其他各種事物可以很方便。)

但有一點需要注意:當你將一個Enemy push_back()放入你的向量時,它實際上是一個存儲的原始實例的副本 這引發了一些問題:首先,對原始內容的更改(例如,對於下面示例的main()范圍中的變量e的成員數據)將不會影響存儲在向量中的副本。 如果你習慣於使用指針向量,這可能會令人驚訝。 其次,隱式構建副本和復制成員數據需要時間,這可能會或可能不會對性能產生重大影響。 第三,隱式構造和復制可能會引發副作用(您應該盡可能在設計中避免使用這些副作用)。

這是一個例子:

#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;
}

如果你想要一個有根據的答案,你必須退后一步 - 設計。 據我所知,Enemy對象通過構造函數在一種全局列表中注冊自己。 到現在為止還挺好。

但是這些物體是如何產生的? 在這個例子中,敵人可以在任何地方構建

  • 在堆棧上作為本地
  • 通過新的(smartpointer)
  • 作為vector,list,deque中的元素...
  • ...

根據這一點,Enemy-object無法對其存儲做任何可靠的陳述。 但是,所有對象共享的一件事以及始終可以從對象內部訪問的東西 - 是地址('this')。 所以通過指針的解決方案是所有構建的敵人對象的唯一解決方案。 (引用在此上下文中也是“一種指針”,而其他更復雜的構造也可能依賴於指針)。

std :: vector無法工作,因為你得到了2個不同的對象。 更改其中一個不會影響另一個。 那不行。 如果不改變您的設計,就無法切換到智能指針。

有兩種常見的解決方案:

以一般方式管理來自“內部”敵人的列表,如給定示例中所示。 通過析構函數自動刪除條目等更多功能可擴展.....

從“外部”管理列表。 敵人對象不會注冊自己,敵人對象的生成器負責做到這一點(在這種情況下,設計模式'工廠'是一個很好的解決方案)。 你可以使用智能指針在大多數情況下這是一個好主意。

還有一些未提及的解決方案(包括一些好的解決方案),它們超出了問題的范圍。

在C ++中你不需要指針(大多數時候)。

使用std::vector::push_back()方法時將進行復制。

例:

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM