Класс, использующий указатель ресурса — класс ресурса с конструктором копирования и оператором присваивания копии

Я создал два простых класса: resource а также container. ниже полный код. на самом деле контейнер хранит ресурсы. и в начале он получит все ресурсы и сохранит их в даталисте ресурсов. Другая функция — просто распечатать все ресурсы в контейнере. Пожалуйста, просмотрите мой код и посмотрите, все ли в порядке, просто просмотрите его и дайте мне знать, какие ошибки и права в коде, спасибо

////
// Created by noone on 18/8/21.
//
#include <iostream>
#include <cstring>
#define Max 10
class resource{
private:
public:
    int id;
    char name[10];

    resource(int id,char name1[10]):id(id)
    {

        std::memcpy(name,name1,Max);
    }
    resource& operator= (const resource& arr2){
        if (this == &arr2){ return *this; } //make sure you aren't self-assigning
        //same as copy constructor from here
        id=arr2.id;
        std::memcpy(name,arr2.name,Max);
        return *this;
    }


};
class container
{
public:
    container(resource *new_resource,int i)
    {
            size=0;
            size=i;
            datalist=(resource *)malloc(sizeof(resource)*i);
            for(int x=0;x<i;x++)
            {
                datalist[x].id=new_resource[x].id;
                std::memcpy(datalist[x].name,new_resource[x].name,std::strlen(new_resource[x].name));

            }


    }
    void print_all_resources()
    {
        std::cout<< "total "<<size<<" resources found"<<std::endl;
        for(int i=0;i<size;i++)
        {
            std::cout<<"Printintg first resource"<<i+1<<std::endl;
            std::cout<<datalist[i].name << " | "<< datalist[i].id<<std::endl;
        }
    }

private:
    resource *datalist;
    int size;
};

int main()
{
    resource resource1(10,"abc");
    resource resource2(20,"xyz");
    resource r[]={resource2,resource1};

    container c(r,2);
    c.print_all_resources();

}

2 ответа
2

Ваш код представляет собой странную смесь C и C ++. По сути, это C с классами (то есть не очень хороший код на C ++).


  1. Использовать constexpr вместо #define для определения констант. constexpr сохраняет информацию о типе.

  2. Использовать std::string вместо массива символов.

  3. Реализуйте правило 0-3-5. Хотя вы определили оператор присваивания копии для resource, вы не определили конструктор копирования или какие-либо конструкторы перемещения / операторы присваивания. Вы также не определили конструкторы / операторы присваивания для container.

  4. Вместо того, чтобы вручную управлять памятью через mallocрассмотрите возможность использования std::vector. Он делает всю тяжелую работу за вас и безопаснее.

  5. Даже если ты хочешь избежать std::vector и самостоятельно управлять памятью (чтобы учиться), вам следует использовать new а также delete вместо malloc а также free.

  6. Говоря о free, Я этого не вижу. У вас утечка памяти, поскольку вы не освобождаете память, выделенную через malloc. В идеале вам нужно создать деструктор, который будет вызывать free когда container объект выходит за пределы области видимости (уничтожается). Это очень важная концепция C ++: Приобретение ресурсов — это инициализация (RAII)

  7. Вместо определения метода с именем print_all_resources, более идиоматическим подходом было бы перегрузить operator<<.

  8. Вместо того, чтобы создавать временный массив и передавать его в container конструктор, вы можете использовать список инициализаторов для передачи произвольного количества resources конструктору.

    container(std::initializer_list<resource> rsc)
    {
       resources.insert(resources.end(), rsc);
    }
     private:
        std::vector<resource> resources;
    

    и назовите это так:

    resource r1;
    resource r2;
    container c({r1, r2});
    
  9. Предпочитаю использовать std::copy над memcpy.

    Если вы использовали string, вам не нужно писать operator= вообще. Вам также не понадобится конструктор копирования, которого нет в вашем коде.

    Ты спрашиваешь

    можешь [sic] покажите, что мой конструктор ресурсов ожидает двух параметров, если я использую new тогда как вызвать конструктор ресурса с двумя параметрами? datalist=new resource[i]; << --- ошибка, конструктор ресурса ожидает два параметра:id,name1 что ты скажешь по этому поводу?

    Если вам нужно было использовать new, вы должны передать такие аргументы:
    resource* p = new resource(name,id);

    Однако я думаю, что на самом деле вам здесь нужно просто vector<resource>. Вам не нужно писать container класс, который хранит динамически выделяемый массив и его размер — в стандартной библиотеке есть готовые контейнеры.

    Вот мой взгляд на это:

    • здесь нет Max.
    struct resource {
       std::string name;
       int id;
       };
    
    std::ostream& operator<< (std::ostream& o, const resource& res);  // write this.
    

    Ты мог написать using resource_container = std::vector<resource>; но ваш код может свободно использовать любой контейнер с resource, а алгоритмам все равно, какой контейнер вы использовали, поэтому этот тип вообще не нужно определять.

    Обратите внимание, что resource не требует конструктора копирования, деструктора или оператора присваивания, поскольку string уже позаботится о себе должным образом. Есть нет требуется особая уборка: это правило нуля.

    Конструктор мне тоже не нужен. Поскольку все элементы данных являются общедоступными, вы можете просто использовать агрегатный инициализатор. Это нормально, поскольку это, по сути, простой пакет данных без специальной проверки соответствия значений или чего-то подобного — любые значения для отдельных полей будут работать.

    Обратите внимание, что с vector ты не звонишь new вообще. Ты только push_back.

    Я думаю, что проблема, о которой вы спрашивали, заключается в том, что для создания массива требуется конструктор по умолчанию. Ваше использование malloc позволяет избежать проблемы, но ничего не исправить: создание «пустого» массива n ресурсы оставляют их неинициализированными в вашем коде или по умолчанию инициализированными в фиксированном коде, но эти элементы массива на самом деле не готовы к использованию, и вам необходимо назначить их поверх них. С vector у вас нет массива n элементы в каком-то пустом состоянии; ты не у вас вообще есть предмет, пока вы не будете готовы его добавить! Увидеть разницу? С vector, у вас никогда не будет лишних неиспользуемых элементов в конце массива; все они допустимые значения.

    vector<resource> Ct;
    Ct.push_back({"name",27});
    Ct.puch_back({"another_with_long_name",42});
    

    Вы также можете создать вектор сразу:

    vector<resource> Container2 {
       {"name",27}, {"another_with_long_name",42}
    };
    

    • If you needed to use new, you would pass the arguments like this: resource* p = new resource(name,id) Я не хочу, чтобы в массиве p содержался единственный объект. Я хотел, чтобы p + i имел доступ к нескольким ресурсам, где i — индекс ресурса в массиве p

      — user786

    • Дело в том, что я не использую строку и вектор, поэтому я могу создать свой собственный контейнер вместо того, чтобы полагаться на контейнеры stl. Хотя мне нравится использовать итератор из stl, встроенный в мой контейнерный класс, как структуру

      — user786


    • resource * p = new resource (name, id) `Я не хочу, чтобы один объект содержался в массиве p. Я хотел, чтобы p + i имел доступ к нескольким ресурсам, где i — индекс ресурса в массиве p. Необходимо выделить все полученные ресурсы и выделить их, вызвав конструктор ресурсов, поэтому выделите массив размеров i.of ресурсов.

      — user786

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *