简体   繁体   English

Unique_Ptr:尝试引用已删除的函数

[英]Unique_Ptr: Attemting To Reference A Deleted Function

So I'm working on a school project right now in C++, although I'm not too familiar with the language yet. 因此,尽管我对这种语言还不太熟悉,但我现在正在使用C ++进行学校项目。 The whole project is divided in several Milestones. 整个项目分为几个里程碑。 1: Reading a list with different Types of Creatures and storing them in a vector 2: Reading a TGA-File and storing it in a class. 1:读取具有不同类型生物的列表并将其存储在矢量中2:读取TGA文件并将其存储在类中。 ... 5: Reading a TGA-Picture for every read Creature-Type and storing it for further use. ... 5:为每个已读取的Creature-Type读取一个TGA图片并将其存储以备将来使用。 (Printing on GUI, Remove/add) (在GUI上打印,删除/添加)

So I thought it is a good idea to store the picture for each type in the class itself, as it should only be loaded once. 因此,我认为将每种类型的图片存储在类本身中是个好主意,因为它只能加载一次。 The load() function in my TGAPicture class will return std::unique_ptr so I added the type as an argument in my CreatureType class. 我的TGAPicture类中的load()函数将返回std :: unique_ptr,因此我在CreatureType类中将类型添加为参数。 After doing that, I got several error like this: 完成此操作后,我得到了如下几个错误:

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  

So I read about 10 questions with similar titles like mine and every one pointed out, that you cant copy unique_ptr and suggested solutions like using std::move() or returning a reference. 因此,我阅读了大约10个问题,这些问题的标题与我的类似,例如我的,每个指出,您不能复制unique_ptr和建议的解决方案,例如使用std :: move()或返回引用。 Although I tried to use these to fix my problem, I wasn't able to do it in the slightest, probably because I'm pretty new to C++ and have never worked with unique pointers. 尽管我尝试使用它们来解决问题,但我丝毫无法做到,这可能是因为我对C ++很陌生,并且从未使用过唯一的指针。

This is the code, that seems relevant to me: 这是代码,似乎与我有关:

/**
 * @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: TGA图片:

//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: 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)};

}

And one class with an error would be: 一个有错误的类是:

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

What do I need to change for it to work? 我需要进行哪些更改才能使其正常工作? And what would be the optimal way? 最佳方法是什么? Pretty sure that I'm supposed to use unique_ptr as return for the TGA::load() method. 非常确定我应该使用unique_ptr作为TGA :: load()方法的返回值。 I hope you can see through this mess and I'd like to apologize if my English isn't perfect, since it's not my first langugage. 希望您能看穿这种混乱局面,如果我的英语不完美,我想表示歉意,因为这不是我的母语。

std::unique_ptr is not copyable. std::unique_ptr不可复制。 It wouldn't be unique anymore if you could copy it. 如果您可以复制它,它将不再是唯一的。

You create copies of the elements in creatureList in your loop in Model 's constructor, but they have a non-copyable member, and so are non-copyable themselves by default. 您可以在Model的构造函数的循环中的creatureList中创建元素的副本 ,但它们具有不可复制的成员,因此默认情况下它们本身也不可复制。 If you don't actually need a copy of the elements, you should use references: 如果您实际上不需要元素的副本,则应使用引用:

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

You haven't actually provided a definition for CreatureList , but I suspect it also isn't copyable. 您实际上尚未提供CreatureList的定义,但我怀疑它也不能复制。 This means that Model::Model 's argument can't be copied into the object's member. 这意味着不能将Model::Model的参数复制到对象的成员中。 You have two options to fix this: make sure to move your CreatureList or make it copyable. 您可以通过以下两种方法解决此问题:确保移动CreatureList或使其可复制。

std::unique_ptr is movable, which means that CreatureType is by default as well, so you can do something like this: 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();
    }
}

This changes Model 's constructor to take its parameter by value and moves that value into the object's creatureList member. 这将更改Model的构造函数以按值获取其参数,并将该值移动到对象的creatureList成员中。

If it makes sense, you could also make CreatureType copyable by adding an explicit copy constructor that copys the object pointed to by picture : 如果有道理,您还可以通过添加显式复制构造函数来复制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))
{
}

If you do that, the implicit move constructor will no longer be generated by the compiler, so you'll want to define that yourself: 如果这样做,编译器将不再生成隐式move构造函数,因此您需要自己定义:

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))
{
}

There doesn't seem to be any reason for TGAPicture::loadPicture to return a std::unique_ptr though. TGAPicture::loadPicture似乎没有任何理由返回std::unique_ptr If you just return by value from that function you will avoid all of these problems: 如果仅从该函数按值返回,则将避免所有这些问题:

TGAPicture TGAPicture::loadPicture(const std::string& path) {
    // ...
    return TGAPicture{pixel, header};
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM