尝试在不使用向量的情况下在C ++中创建许多相同类的对象

问题描述

因此,我的目标是创建多个相同类的对象,而无需多次复制一个对象。我想我找到了一种方法方法是将一个指针数组指向某个对象,但出现分段错误

不幸的是,在这个项目中,我试图做的是,我没有使用280dp以外的任何其他库(我必须在这里添加,该类的构造函数将一些参数作为输入)。

有想法吗?

代码如下:

<cstring>

...以及该类的代码

#include <iostream>
#include <cstring>
using namespace std;

int main(void)
{
    int i,floor,classroom; //the floor of the school and the classroom the student is heading to
    char *stname;
    typedef Student *stptr;
    stptr *students = new stptr[15];
    for (i = 0; i < 15; i++)
    {
        cin >> stname;
        cin >> floor;
        cin >> classroom;
        students[i] = new Student(stname,classroom);
    }
}

解决方法

我建议不要进行这种指针混淆:

Student** students = new Student*[15];

更容易理解IMO。

您可以使用C ++专有的工具来自动处理对象的字符串数组:

std::string表示字符串;

std::vector用于阵列。

对象指针在多态环境中很有用,但即使那样,最好使用smart pointers

pointed out by marcinj in the comments一样,name声明也需要修正。

pointed out by Alan Birtles也在使用stname未初始化,这可能是段错误的罪魁祸首。

要修复您的代码,请使用当前使用的工具执行类似以下代码的操作,请注意,除修复外,还必须遵守rule of three

#include <iostream>
#include <cstring>
class Student {
    char *name;
    int no_floor;
    int no_classroom;
public:
    Student(const char *nam,int no_fl,int no_cla){//constructor  
        name = new char[strlen(nam) + 1];
        strcpy(name,nam);
        no_floor = no_fl;
        no_classroom = no_cla;       
        std::cout << "A new student has been created! with name " << name << " heading to floor: " << no_floor << " class: " << no_classroom << std::endl;
    };
    ~Student(){//destructor    
      std::cout << "A Student to be destroyed! with name " << name << " is at floor: " << no_floor << " class: " << no_classroom;
      delete [] name;
    };    
    Student (const Student& student) { //copy constructor
        this->name = nullptr;
        *this = student;
    } 
    Student& operator = (const Student& student){ //assignment operator
        if(this == &student){
            return *this;
        }
        delete [] this->name;
        this->name = new char[strlen(student.name) + 1];
        strcpy(this->name,student.name);
        this->no_classroom = student.no_classroom;
        this->no_floor = student.no_floor;        
        return *this;
    }
};
int main(){

    int i,floor,classroom;
    char *stname = new char[100];
    typedef Student *stptr;
    stptr *students = new stptr[15];

    for (i = 0; i < 15; i++){

        std::cin >> stname;
        std::cin >> floor;
        std::cin >> classroom;
        students[i] = new Student(stname,classroom);
    }
    delete [] stname;

    for (i = 0; i < 15; i++){
        delete students[i];
    }
    //or for the deletion in inverse order
    //for (i = 2; i >= 0; i--){ 
    //    delete students[i];
    //}
    delete [] students;

}
,

此代码中无需使用指针,使用对象数组而不是指针,而使用std::string而不是char*可以使您的代码更加简单和安全:

#include <iostream>
#include <string>

class Student
{
private:
    std::string name;
    int no_floor;
    int no_classroom;
public:
    Student() = default;

    Student(const std::string& nam,int no_cla) //constructor
    : name(nam),no_floor(no_fl),no_classroom(no_cla)
    {
        std::cout << "A new student has been created! with name " << name << " heading to floor: " << no_floor << " class: " << no_classroom << std::endl;
    };

    ~Student() //destructor
    {
        std::cout << "A Student to be destroyed! with name " << name << " is at floor: " << no_floor << " class: " << no_classroom;
    };
};

int main(void)
{
    int i,classroom; //the floor of the school and the classroom the student is heading to
    std::string stname;
    Student students[15];
    for (i = 0; i < 15; i++)
    {
        std::cin >> stname;
        std::cin >> floor;
        std::cin >> classroom;
        students[i] = Student(stname,classroom);
    }
}

原始代码中存在许多问题。

  1. stname未初始化,因此读入它会导致不确定的行为。您需要使用数组初始化它,例如char *stname = new char[100],您必须记住在程序结束时delete,以避免内存泄漏。还要注意,std::cin >> stname是不安全的,因为它不知道数组的长度,因此,如果您读取的字符数超过了适合的字符数,将导致不确定的行为。或者,您可以只使用固定长度的数组,这至少解决了必须记住调用deletechar stname[100]
  2. 的问题
  3. 您永远不会deletestudents本身的元素导致内存泄漏。
  4. students返回字符串的长度,该字符串的长度从您实际想要的第二个字符开始,strlen(nam + 1)返回字符串的长度加上一个空终止符。
  5. 这还没有给您带来问题,但是您需要实现rule of three并添加一个复制构造函数和赋值运算符

当您不使用原始指针时,所有这四个问题都会消失...

如果您真的不能使用strlen(nam) + 1,则最好的方法可能是创建自己的字符串类,然后使用该字符串类,以便将所有原始指针crud至少限制在一个位置。例如这样的东西:

std::string

是的,虽然有很多代码,但是如果您的老师对class String { public: String() :str(nullptr),length(0),capacity(0) { } String(const char* s) :String() { assign(s); } String(const String& other) :String() { assign(other.str,other.length); } String& operator = (const String& other) { assign(other.str,other.length); return *this; } ~String() { delete[] str; } void reserve(size_t new_capacity) { // note doens't copy existing data in str to new buffer delete str; str = new char[new_capacity + 1]; capacity = new_capacity; } friend std::ostream& operator <<(std::ostream& os,const String& str) { if (str.length) { os.write(str.str,str.length); } return os; } friend std::istream& operator >>(std::istream& is,String& str) { // note can only read up to 100 characters str.reserve(100); str.length = 0; std::istream::sentry sentry(is); if (sentry) { while (str.length < str.capacity) { auto ch = is.rdbuf()->sgetc(); if (!std::istream::traits_type::not_eof(ch)) { is.setstate(std::ios_base::eofbit); break; } if (std::isspace(ch)) { break; } str.str[str.length++] = ch; is.rdbuf()->sbumpc(); } } str.str[str.length] = '\0'; return is; } private: void assign(const char* s) { size_t len = strlen(s); assign(s,len); } void assign(const char* s,size_t len) { if (len > 0) { if (len > capacity) { reserve(len); } strcpy(str,s); } length = len; } char* str; size_t length; size_t capacity; }; 过敏,这是使代码正确所需要的最低要求。

,

尽管我同意@anastaciu的评论,但我也建议避免使用原始指针,因为如果您不熟悉C / C ++,可能会遇到很多问题,例如dangling pointers,{{ 3}}和wild pointers。您应该避免使用它们,除非有必要(例如,内存映射的IO或memory leaks,因为您无法想到另一种方法),或者使用内置的容器放置对象(您可以了解关于它们的更多信息unsafe casts

,

好的,我找到了@Alan Birtles答案中出现的双重破坏打印的解决方案。您可以以不同的方式分配内存,而无需复制对象然后销毁它。这是代码:

int i,classroom;
   string stname;
   Student* students[5];
   for(i=0; i<5; i++)
   {
      cin >> stname;
      cin >> floor;
      cin >> classroom;
      students[i] = new Student(stname,classroom);
   }
   for(i=0; i<5; i++)
   {
     delete students[i];
   }

..然后就可以了!