既然可以使用=运算符给字符串赋值,为什么还要在赋值前使用new运算符动态分配内存给字符串呢?

why use the new operator to dynamically allocate memory for a string before assigning, when we can use the = operator to assign a string to it?

我是 C++ 和字符串概念的新手,为什么我必须使用 new 运算符来动态分配资源,而我可以使用 = 运算符分配字符串? (这是我的第一个问题,抱歉打扰了)

student(const char* n){
    len=strlen(n);
    name=new[len+1];
    strcpy(name,n);
}

其中学生是 class 学生的动态构造函数。

class student {
    int len; 
    char *name; 
public: 
    student(const char *);
}

如果我如下所示编写我的动态构造函数,它不会有相同的结果吗?

student(const char* n){
    len=strlen(n); 
    name=n;
}

A char * s; 不是字符串。它是一个指针——句柄——指向一个内存块,其中该块的每个元素都是 char.

的大小

您必须使用new分配一个盒子。

然后你 "attach" 那个盒子的句柄。

然后用数据填充方框——这就是字符串。

// we have a handle which will fit a box that contains a bunch of "char"
char * s;
// now let's get a box that's big enough to hold the data
// and attach it to the handle
s = new char [len];
// now let's fill up the box with the data from source_str
strcpy (source_str, s);
// also, don't forget that you MUST delete anything that you allocate
delete [] s;

这是编程中一个极其重要的概念,尤其是对于像 C++ 这样的系统语言。

C++ 和其他支持 classes 和对象的语言使用构造函数和析构函数来帮助控制对象通过以下循环使用的任何内存:

  • 构建对象
  • 对对象做点什么
  • 销毁对象

请注意这与内存管理的循环完全相同。

你现在练习弦乐的原因是让你习惯以下技巧:

  • 分配一块内存
  • 用它做点什么
  • 稍后释放那块内存

这是一个简单的例子:

#include <iostream>
using namespace std;

char * get_a_string () {
    // notice that s is allocated "on the stack"
    // which means that it goes out of scope and is
    // not available outside of this function
    auto s = "Adam Smith";

    //char * name = s;  // this WILL NOT WORK because the memory that
                        // that s points to will go out of scope
                        // and then name will point to invalid memory

    // we need to make s available to other parts of the
    // program so we allocate some memory "on the heap"
    // because the heap doesn't go out of scope
    char * name = new char [strlen (s)];

    // now since the contents of s have been copied into the heap
    // they'll still be available outside of this function
    strcpy (s, name);

    return name;
}

void do_something (char * c) {
    cout << c << endl;
}

int main () {    
    char * name = get_a_string ();

    do_something (name);

    // rule of thumb:
    //     anything you allocate with "[]" you must also delete with "[]"...
    delete [] name;
}

注意上面程序中内存的循环。注意它是 "newed-up" 和 "deleted"。跟踪哪些函数分配了内存,哪些函数删除了它,以便您可以在适当的时间新建和删除,这不是很棘手吗?

这是一个学生 class 的例子,与您想要的相似。请注意内存是如何分配在一个地方并且易于跟踪的:

#include <iostream>
using namespace std;

class Student {
    public:
        // This is NOT a string.
        // It does not contain any data.
        // It only points to a block/box of data that is
        // split into chunks the size of a char
        char * my_name;

        Student (const char * new_name) {
            // we have to find out how long new_name is
            auto name_len = strlen (new_name);

            // now we need to make a box big enough to hold it
            // this is called allocation
            my_name = new char [name_len];

            // now we must copy the contents from the box that
            // new_name points to into the box that my_name points to
            strcpy (new_name, my_name);
        }

        ~Student () {
            // it's very important to free up the memory we allocated
            // in the constructor
            delete [] my_name;
        }
};

int main () {
    // so here the name is allocated and initialized so that we can use some_student elsewhere in our program
    Student some_student ("Adam Smith");

    // making use of the block of memory...
    cout << "student's name is: " << some_student.my_name << endl;

    return 0;
}
// at the end of the scope the destructor for some_student will be called
// which will delete some_student.my_name so that other programs can use
// that memory

这种现代方法使用 std::string 但它仍然是完全相同的东西

是的。 std::string 与您的简单学生 class 所做的完全相同

#include <string>

class Student {
    public:
        std::string name;

        Student (const char * s) {
            // name is a std::string
            // that means that std::string has a constructor
            // and a copy operator which will do exactly what you
            // were doing using new and delete
            // It's just hidden and done for us BUT IT'S STILL BEING DONE.
            name = s;
        }

        ~Student () {
            // ...
        }
        // destructors for all of a class' members will be
        // called at the end of a class' destructor!
        // this means that since "my_name" is a std::string
        // its destructor will delete the memory that std::string
        // allocated in its constructor for me and I don't have to
        // do anything!
};

int main () {
    // so here the name is allocated and initialized
    // so that we can use some_student elsewhere in our program
    auto some_student = Student { "Adam Smith" };

    // making use of the block of memory...
    cout << "student's name is: " << some_student.my_name << endl;

    return 0;
}
// at the end of the scope the destructor for some_student will be called
// which will delete some_student.my_name so that other programs can use
// that memory

以下是 Bjarne Stroustrup 对 learning to program using C++ 的评价。

分配您拥有的缓冲区时,您可以修改它,但也必须删除它。

我认为上面的案例不应该编译。您正在将编译器不允许的 const char * 分配给 char *。如果您将成员更改为 const char*,您仍然可能将一个字符串交给构造函数,该字符串后来不复存在,然后您得到一个错误的指针。

唯一无关紧要的情况是,如果您知道您正在分配常量字符串,例如 `const char * var="my literal string".