how to design class that has char* pointer as clas

2019-09-09 23:28发布

问题:

First i want to introduce my situation :

I have write some classes that has char* pointer as private class member.And also this project has GUI, so when click buttons,some functions may execute more than one time.Those classes are designed single class in project.But some functions of them can execute more than one time.Then I found my project has memory leak.

so i want to ask the following questions:

  1. how to design the set function?
  2. how to design the other functions that use the char* member variable?
  3. how to design the class operator= function?

for example:

class A:
{
 public :
 setStr(char * s){//need new or just use =?};
 A & operator=(const A& other){//also need new?};
 manyTimesFunctions(char * other)
 {
  //need to use chars other to assignment str
  //how to carefully use new to avoid memory leak?
  //other may be another class's locality none const variable 

 } 
 private:
 char * str;
}

So ,the project only init class A once,but may use setStr and manyTimesFunctions many times.


May be the answer:

I think i have found what i need to take care of:copy that class,that answers are really useful to me.

回答1:

This answer will be used to contrast what the other answer(s) given that state to use std::string (and those answers are correct -- use std::string).

Let's assume that you could only use char *, you can't for some reason use std::string, and that you are dealing with NULL terminated strings. This is a synopsis of what your implementation would have to do (and please compare this with simply using std::string):

#include <algorithm>
#include <cstring>

class A
{
    public:
       // construct empty string
       A () : str(new char[1]()) {}

       // construct from non-empty
       A(const char *s) : str(new char[strlen(s) + 1])
       { strcpy(str, s); }

       // copy construct
       A(const A& rhs) : str(new char[strlen(rhs.str) + 1])
       { strcpy(str, rhs.str); }

       // destruct
       ~A() { delete [] str; }

       // assign
       A& operator=(const A& rhs)
       {
          A temp(rhs);
          std::swap(str, temp.str);
          return *this;
       }

       // setter
       void setStr(char * s)
       {
          A temp(s);
          *this = temp;
       }  

       // getter
       const char* getStr() { return str; }

     private:
        char * str;
};

Live Example

After adding a couple more constructors and a getter function, this follows the Rule of 3.

You see how much code we needed to add just to make the class safely copyable and assignable? That's why using std::string is much more convenient than using char * when it comes to class members. For std::string a single line needs to be changed, compared to adding the copy / assignment (and move, which I didn't show) functions.

The bottom line is that in C++ if you want strings, use strings (std::string) and try to keep away from using char * (unless you have a very compelling reason to be using char * to represent string data).



回答2:

Just use std::string. It takes care of memory management for you. The member declaration then looks like

std::string str;

and the setter function looks like

void setStr( char const* s ) { str = s; }

Where you want to use the string and need a char const*, just write str.c_str().

With use of standard library types like std::string, and no manual dynamic allocation, you generally don't need to be concerned about operator=: the compiler-generated copy assignment works nicely.


By the way, it's generally a good idea to decide on some naming convention for member variables. Common ones for C++ include str_, mStr, and my_str. The underscore suffix is perhaps the most common one, but don't use a leading underscore like _str, because although technically allowed it conflicts with the conventions for implementation defined names (e.g. leading underscore is not allowed for identifiers in the global namespace).



回答3:

I am not 100% sure what you are trying to do. However, since char* is a pointer you may be able to simply pass around the references.

char* operator=(char* s) { str = s; }

Just know that then if you modify value in your function it will modify the place you copied it from

If the char* needs to actually be a clone, so that it does not modify the original value. You first need to obtain the length of the char*.

This can be done with this function

unsigned Length(char* s)
{
   unsigned I = 0;
   while( *(s+I) != '\0')
      I++;

   return I;
}

The a new string can be created as follows

str = new char[LENGTH];

At that point you can copy the string over term by term

for(I = 0 ; I < LENGTH; I++)
{
   str[I] = s[I];
}

Finally to avoid memory leaks this needs to be deleted in the class destructor

~A()
{
    delete [] str;
}

Of course using std::string could save a lot of problems.