简体   繁体   中英

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?

I am new to C++ and the concept of strings, why do I have to use the new operator to dynamically allocate resources when I can do it just assigning the string using the = operator ? (this is my first question and sorry for being messy)

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

where student is a dynamic constructor of class student.

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

If I write my dynamic constructor as given below, will it not have the same outcome?

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

A char * s; is not a string. It's a pointer-- a handle -- to a block of memory in which each element of that block is the size of a char .

You have to use new to allocate a box.

Then you "attach" your handle to that box.

Then you fill up the box with data-- this is the string.

// 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;

This is an extremely important concept in programming especially for system languages like C++.

C++, and other languages that support classes and objects use constructors and destructors to help control any memory that an object uses by following this cycle:

  • construct the object
  • do something with the object
  • destruct the object

Notice how this is exactly the same as the cycle of memory management.

The reason you're practicing on strings right now is to get you used to the technique of:

  • allocating a block of memory
  • doing something with it
  • then freeing up that block of memory later

Here's a straight-forward example:

#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;
}

Pay careful attention to the cycle of memory in the above program. Notice when it's "newed-up" and "deleted". Wouldn't it be tricky to keep track of which functions allocated memory and which ones deleted it so that you could new and delete at the proper times?

Here's an example of a Student class similar to what you're going for. Notice how the memory is allocated in one place and is easy to track:

#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

This modern approach uses std::string but it is still exactly the same thing .

YES. std::string does exactly the same thing that your simple Student class does .

#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

Here's what Bjarne Stroustrup had to say about learning to program using C++ .

When you allocate the buffer you own it, you can modify it but you also must delete it.

I do not think the above case should compile. You are assigning const char * to char * that should not be allowed by the compiler. If you changed your member to be const char* you still could possibly hand over to the constructor a string that later ceases to exist and then you got a bad pointer.

the only time it should not matter is if you know that you are assigning constant strings such as `const char * var="my literal string".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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