Unique_Ptr:注意引用已删除的函数

时间:2017-06-29 21:11:07

标签: c++ reference move unique-ptr

所以我现在正在用C ++开展一个学校项目,虽然我还不太熟悉这门语言。 整个项目分为几个里程碑。 1:读取具有不同生物类型的列表并将其存储在矢量中 2:读取TGA文件并将其存储在类中。 ... 5:为每个读取的Creature-Type读取TGA-Picture并存储以供进一步使用。 (在GUI上打印,删除/添加)

所以我认为在类本身中存储每种类型的图片是个好主意,因为它只应加载一次。 我的TGAPicture类中的load()函数将返回std :: unique_ptr,所以我在CreatureType类中添加了类型作为参数。 在这之后,我得到了几个这样的错误:

Error   C2280   'biosim::CreatureType::CreatureType(const biosim::CreatureType &)': attempting to reference a deleted function  bio-sim-qt  E:\Development\C++\bio-sim-qt\bio-sim-qt\qtmain.cpp 58  1   

Error (active)      function "biosim::CreatureType::CreatureType(const biosim::CreatureType &)" (declared implicitly) cannot be referenced -- it is a deleted function  bio-sim-qt  e:\Development\C++\bio-sim-qt\bio-sim-qt\Model.cpp  15  26  

所以我读了大约10个类似标题的问题,每个人都指出,你不能复制unique_ptr和建议的解决方案,比如使用std :: move()或返回引用。 虽然我试图用这些来解决我的问题,但我无法做到这一点,可能是因为我对C ++很陌生并且从未使用过独特的指针。

这是与我相关的代码:

/**
 * @class CreatureType
 * Object of the various CreatureTypes ingame
 */
class CreatureType {

    private:
    std::string name;
    int strengh;
    int speed;
    int lifespan;
    std::vector<std::string> attributes;
    std::string path;
    std::unique_ptr<TGAPicture> picture; //What I tried to add in order to stre my pictures

    public:
    CreatureType(const std::string& name
                , int strengh, int speed, int lifespan
                , const std::vector<std::string>& basic_strings
                , const std::string& path);

    /**
    * Initializes list with CreatureTypes by reading from a .txt-File
    */
    static CreatureList load(const std::string& file);

    /**
     * Printing Data in various ways
     */
    void getInfo() const;
    void getInfoInOneLine() const;

    std::string getName() const;
    int getStrengh() const;
    int getSpeed() const;
    int getLifespan() const;
    std::vector<std::string> getAttributes() const;
    std::string getPath() const;
};

}

CreatureType::CreatureType(const std::string& name
                            , int strengh, int speed, int lifespan
                            , const std::vector<std::string>& basic_strings
                            , const std::string& path)
    : name(name),
    strengh(strengh),
    speed(speed),
    lifespan(lifespan),
    attributes(basic_strings),
    path(path),
    picture(TGAPicture::loadPicture(Reference::PicturePath::creatureBasePath + path)){ }

/**
 * Implementation Notes:
 * - Does a line not fullfill the requirenments, it will be ignored
 * - @see <a href="https://elearning.uni-bayreuth.de/pluginfile.php/644828/mod_resource/content/2/Aufgabenblatt_1.pdf">Formation</a>
 * - Prints data with std::cout
 */
CreatureList CreatureType::load(const std::string& file) {
    CreatureList creatureList;
    std::ifstream fileStream; //Datei-Handle
    int lineNumber = 0;
    int correctLinesRead = 0;


    fileStream.open(file, std::ios::in);
    if (!fileStream.is_open()) {
        throw FileNotFoundException(file);
    }

    logger << INFO << "Einlesevorgang wird gestartet\n";

    //One line per loop
    while (!fileStream.eof()) {
        bool skipLine = false;

        std::string line;
        getline(fileStream, line);
        lineNumber++;

        ... //Checking if data is valid 


        //Every Parameter does exist and is valid
        creatureList.push_back(CreatureType(creatureArgs[0]
                                            , strengh, speed, lifespan
                                            , attributes, creatureArgs[5]));
        correctLinesRead++;
    }

return creatureList;
}

TGAPicture:

//no padding bytes
#pragma pack( push, 1 )
/**
 * @struct TGAHeader
 * Represents the standard TGA-Header.
 */
struct TGAHeader {
    char idLength;
    char colourmapType;
    char imagetype;

    short colourmapStart;
    short colourmapLength;
    char colourmapBits;

    short xOrigin;
    short yOrigin;
    short width;
    short height;
    char bits;
    char descriptor;

};
#pragma pack( pop )


/**
* @struct RGBA
* Represents a Pixel with a red, green, blue and possibly alpha value
*/
struct RGBA {
    std::uint8_t B, G, R, A;
};

/**
* @class TGAPicture
* Class used to represent TGA-Files, that are used in the program
*/
class TGAPicture {

    public:
    TGAPicture(const TGAPicture& other)
        : pixel(other.pixel),
        header(other.header),
        width(other.width),
        height(other.height),
        size(other.size),
        bitsPerPixel(other.bitsPerPixel) {}

    TGAPicture(TGAPicture&& other) noexcept
        : pixel(std::move(other.pixel)),
        header(std::move(other.header)),
        width(other.width),
        height(other.height),
        size(other.size),
        bitsPerPixel(other.bitsPerPixel) {}

    TGAPicture& operator=(const TGAPicture& other) {
        if (this == &other)
            return *this;
        pixel = other.pixel;
        header = other.header;
        width = other.width;
        height = other.height;
        size = other.size;
        bitsPerPixel = other.bitsPerPixel;
        return *this;
    }

    TGAPicture& operator=(TGAPicture&& other) noexcept {
        if (this == &other)
            return *this;
        pixel = std::move(other.pixel);
        header = std::move(other.header);
        width = other.width;
        height = other.height;
        size = other.size;
        bitsPerPixel = other.bitsPerPixel;
        return *this;
    }

    private:
    std::vector<RGBA> pixel; //Containes every pixel of the picture
    TGAHeader header;
    short width, height, size, bitsPerPixel;

    ...

    public:
    /**
    * Loads and initializes a picture to be used in the program
    * @throws TGAExpection if file could not be loaded
    */
    static std::unique_ptr<TGAPicture> loadPicture(const std::string& path);
    TGAPicture(const std::vector<RGBA>& pixel, const TGAHeader& header);
    ~TGAPicture();
    ....
};
}
#endif

CPP:

TGAPicture::TGAPicture(const std::vector<RGBA>& pixel, const TGAHeader& header)
    : pixel(pixel),
    header(header),
    width(header.width),
    height(header.height),
    size(header.width * header.height * (header.bits / 8)),
    bitsPerPixel(header.bits) { }



std::unique_ptr<TGAPicture> TGAPicture::loadPicture(const std::string& path) {
    ...


    for (int i = 0; i < header.height * header.width; i++) {
        pixel[i].B = *(bufferPosition++);
        pixel[i].G = *(bufferPosition++);
        pixel[i].R = *(bufferPosition++);
        pixel[i].A = (header.bits > 24 ? *(bufferPosition++) : 0xFF);
    }

    /**
     * Return unique_ptr
     * - ObjectFactory
     * - Automatic Deletion
     */
    return std::unique_ptr<TGAPicture>{new TGAPicture(pixel, header)};

}

有一个错误的类是:

class Model {

    public:
    explicit Model(const CreatureList& creatureList);
    ~Model();


    Terrain* getTerrain() const;
    CreatureList& getCreatureList();

    private:
    CreatureList creatureList;
    Terrain* terrain;

};


Model::Model(const CreatureList& creatureList) : creatureList(creatureList),
                                                terrain(new Terrain()) {

    for (CreatureType ty : creatureList) {  //line with errror
        ty.getInfoInOneLine();
    }
}

我需要改变它才能发挥作用?什么是最佳方式?很确定我应该使用unique_ptr作为TGA :: load()方法的返回。 我希望你能看透这个烂摊子,如果我的英语不完美,我想道歉,因为这不是我的第一个langugage。

1 个答案:

答案 0 :(得分:2)

std::unique_ptr不可复制。如果你可以复制它,它将不再是唯一的。

您在creatureList构造函数的循环中Model创建了副本,但是他们有一个不可复制的成员,所以默认情况下不可复制。如果您实际上不需要元素的副本,则应使用引用:

Model::Model(const CreatureList& creatureList)
    : creatureList(creatureList),
      terrain(new Terrain())
{
    for (CreatureType& ty : creatureList) {  // changed to reference instead
                                             // Note: this is still working with
                                             //       parameter, not the object's
                                             //       member.
        ty.getInfoInOneLine();
    }
}

您还没有为CreatureList提供定义,但我怀疑它也不可复制。这意味着Model::Model的参数无法复制到对象的成员中。您有两种方法可以解决此问题:确保移动CreatureList或将其设为可复制。

std::unique_ptr是可移动的,这意味着CreatureType也是默认的,所以你可以这样做:

Model::Model(CreatureList creatureList)  // Take by value now
    : creatureList(std::move(creatureList)),  // Move the parameter to the member
      terrain(new Terrain())
{
    for (CreatureType& ty : this->creatureList) {  // Use this-> to access member
                                                   // instead of now moved-from
                                                   // parameter.  You could also
                                                   // just change them to have
                                                   // different names.
        ty.getInfoInOneLine();
    }
}

这会更改Model的构造函数以按值获取其参数,并将该值移动到对象的creatureList成员中。

如果有意义,您还可以通过添加一个显式复制构造函数来复制CreatureType,该复制构造函数复制picture指向的对象:

CreatureType::CreatureType(const CreatureType& other)
    : name(other.name),
      strengh(other.strengh),
      speed(other.speed),
      lifespan(other.lifespan),
      attributes(other.attributes),
      path(other.path),
      picture(new TGAPicture(*other.picture))
{
}

如果这样做,编译器将不再生成隐式移动构造函数,因此您需要自己定义:

CreatureType::CreatureType(CreatureType&& other)
    : name(std::move(other.name)),
      strengh(other.strengh),
      speed(other.speed),
      lifespan(other.lifespan),
      attributes(std::move(other.attributes)),
      path(std::move(other.path)),
      picture(std::move(other.picture))
{
}

TGAPicture::loadPicture似乎没有任何理由让std::unique_ptr返回TGAPicture TGAPicture::loadPicture(const std::string& path) { // ... return TGAPicture{pixel, header}; } 。如果你只是从该函数返回值,你将避免所有这些问题:

<div class="">
    <a href="#" data-url="hMxGhHNOkCU">A</a>
    <a href="#" data-url="BWXggB-T1jQ">B</a>
    <a href="#" data-url="gqOEoUR5RHg">C</a>
    <a href="#" data-url="5GcQtLDGXy8">D</a>
    And so on till Z
</div>