When I initialize the constructor with the given data type of the parameter, I find that it goes wrong with the explaination that " const char* values cannot be assigned to char* entities".
class TString
{
private:
char* m_pData;
int m_nLength;
public:
TString();
TString(const char* pStr);
······
}
TString::TString(const char* pStr) {
this->m_pData = pStr;
}
What should I do to solve this problem? If possible, give me a right example.
Thanks in advance and apolpgize for my ignorance.
Const char * generally are prefined static compiled strings that cannot be changed because they are locked in the source code, or they come from some immutable source. This is in part, why they are marked const to prevent people from trying to change them.
The easiest solution to this problem is to take the const char * and make a copy of it on the heap, then it is no longer constant.
For example:
#include <string.h> // for strdup
...
TString::TString(const char* pStr) {
m_pData = strdup(pStr); // this will malloc and copy the string accepting const char * as input.
}
One thing you will need to consider, the m_pData is now on the heap, so in the destructor, you will want to free this data otherwise you will have a memory leak.
TString::~TString(){
free(m_pData);
}
You will also want in the TString() constructor to set the m_pData=NULL too.
This will work with strings, but if it's binary data i.e. no terminator allocate the data using malloc and use a memcpy, like:
m_pData=(char *)malloc(m_nlength*sizeof(char));
memcpy(m_pData,pStr,m_nlength);
Or some such.
Related
I have been given this definitions, the function should return what is in info->phrase. However info->phrase can contain a string in which case I can only make it return the first char on info->phrase. Is there a way to make a string compatible with the char type? I am new to c++.
struct rep_info {
int num;
char *phrase;
};
I´ve tried few thing but get type errors, this was my latest attempt
char *phrase_info(rep_info info) {
char text[std::strlen(info->phrase) + 1];
text = info->phrase;
return text;
}
Since you said you have been given these definitions, let's fix the problem with the current setup first. Looking at your function, you are trying to copy into this local array (incorrectly I might add), and return this local variable. There are a number of things wrong with this, including the syntax and the fact that the local variable is destroyed when the function exits.
If you just need to get the value of the phrase member variable, the simplest solution would be to just access the member variable directly and return it:
char *phrase_info(rep_info info) {
return info.phrase; //since info is not a pointer, use the '.' accessor
}
If you mean to pass a pointer to the function, you would re-write it like this:
char *phrase_info(rep_info *info) {
return info->phrase;
}
But it seems like you feel the need to copy the contents of info->phrase into a new memory space? If so, then you would do something like this where you first allocate new memory and return this buffer:
char *phrase_info(rep_info *info) {
char *buf = new char[std::strlen(info->phrase) + 1];
std::strcpy(buf,info->phrase); //copies info->phrase into buf
return buf;
}
You would then need to use delete on the returned memory value to clean up the memory allocated by new, otherwise you will have a memory leak.
Overall, all the above solution would potentially solve the problem given some parameters you haven't made clear. To round this out, this should be written more like:
class rep_info {
private:
int num;
std::string phrase;
public:
rep_info(int n, std::string p) : num(n), phrase(p) {}
std::string get_phrase() { return phrase; }
// other functions
};
//later in the code
rep_info info(...);
info.get_phrase();
Ideally, you would wrap these member variables into their own object with corresponding member functions that can get and set these values. Moreover, for handling strings in C++, std::string is the preferred option for storing, copying, modifying, etc. strings over the older char * C-style string.
It might not be advisable according to what I have read at a couple of places (and that's probably the reason std::string doesn't do it already), but in a controlled environment and with careful usage, I think it might be ok to write a string class which can be implicitly converted to a proper writable char buffer when needed by third party library methods (which take only char* as an argument), and still behave like a modern string having methods like Find(), Split(), SubString() etc. While I can try to implement the usual other string manipulation methods later, I first wanted to ask about the efficient and safe way to do this main task. Currently, we have to allocate a char array of roughly the maximum size of the char* output that is expected from the third party method, pass it there, then convert the return char* to a std::string to be able to use the convenient methods it allows, then again pass its (const char*) result to another method using string.c_str(). This is both lengthy and makes the code look a little messy.
Here is my very initial implementation so far:
MyString.h
#pragma once
#include<string>
using namespace std;
class MyString
{
private:
bool mBufferInitialized;
size_t mAllocSize;
string mString;
char *mBuffer;
public:
MyString(size_t size);
MyString(const char* cstr);
MyString();
~MyString();
operator char*() { return GetBuffer(); }
operator const char*() { return GetAsConstChar(); }
const char* GetAsConstChar() { InvalidateBuffer(); return mString.c_str(); }
private:
char* GetBuffer();
void InvalidateBuffer();
};
MyString.cpp
#include "MyString.h"
MyString::MyString(size_t size)
:mAllocSize(size)
,mBufferInitialized(false)
,mBuffer(nullptr)
{
mString.reserve(size);
}
MyString::MyString(const char * cstr)
:MyString()
{
mString.assign(cstr);
}
MyString::MyString()
:MyString((size_t)1024)
{
}
MyString::~MyString()
{
if (mBufferInitialized)
delete[] mBuffer;
}
char * MyString::GetBuffer()
{
if (!mBufferInitialized)
{
mBuffer = new char[mAllocSize]{ '\0' };
mBufferInitialized = true;
}
if (mString.length() > 0)
memcpy(mBuffer, mString.c_str(), mString.length());
return mBuffer;
}
void MyString::InvalidateBuffer()
{
if (mBufferInitialized && mBuffer && strlen(mBuffer) > 0)
{
mString.assign(mBuffer);
mBuffer[0] = '\0';
}
}
Sample usage (main.cpp)
#include "MyString.h"
#include <iostream>
void testSetChars(char * name)
{
if (!name)
return;
//This length is not known to us, but the maximum
//return length is known for each function.
char str[] = "random random name";
strcpy_s(name, strlen(str) + 1, str);
}
int main(int, char*)
{
MyString cs("test initializer");
cout << cs.GetAsConstChar() << '\n';
testSetChars(cs);
cout << cs.GetAsConstChar() << '\n';
getchar();
return 0;
}
Now, I plan to call the InvalidateBuffer() in almost all the methods before doing anything else. Now some of my questions are :
Is there a better way to do it in terms of memory/performance and/or safety, especially in C++ 11 (apart from the usual move constructor/assignment operators which I plan to add to it soon)?
I had initially implemented the 'buffer' using a std::vector of chars, which was easier to implement and more C++ like, but was concerned about performance. So the GetBuffer() method would just return the beginning pointer of the resized vector of . Do you think there are any major pros/cons of using a vector instead of char* here?
I plan to add wide char support to it later. Do you think a union of two structs : {char,string} and {wchar_t, wstring} would be the way to go for that purpose (it will be only one of these two at a time)?
Is it too much overkill rather than just doing the usual way of passing char array pointer, converting to a std::string and doing our work with it. The third party function calls expecting char* arguments are used heavily in the code and I plan to completely replace both char* and std::string with this new string if it works.
Thank you for your patience and help!
If I understood you correctly, you want this to work:
mystring foo;
c_function(foo);
// use the filled foo
with a c_function like ...
void c_function(char * dest) {
strcpy(dest, "FOOOOO");
}
Instead, I propose this (ideone example):
template<std::size_t max>
struct string_filler {
char data[max+1];
std::string & destination;
string_filler(std::string & d) : destination(d) {
data[0] = '\0'; // paranoia
}
~string_filler() {
destination = data;
}
operator char *() {
return data;
}
};
and using it like:
std::string foo;
c_function(string_filler<80>{foo});
This way you provide a "normal" buffer to the C function with a maximum that you specify (which you should know either way ... otherwise calling the function would be unsafe). On destruction of the temporary (which, according to the standard, must happen after that expression with the function call) the string is copied (using std::string assignment operator) into a buffer managed by the std::string.
Addressing your questions:
Do you think there are any major pros/cons of using a vector instead of char* here?
Yes: Using a vector frees your from manual memory management. This is a huge pro.
I plan to add wide char support to it later. Do you think a union of two structs : {char,string} and {wchar_t, wstring} would be the way to go for that purpose (it will be only one of these two at a time)?
A union is a bad idea. How do you know which member is currently active? You need a flag outside of the union. Do you really want every string to carry that around? Instead look what the standard library is doing: It's using templates to provide this abstraction.
Is it too much overkill [..]
Writing a string class? Yes, way too much.
What you want to do already exists. For example with this plain old C function:
/**
* Write n characters into buffer.
* n cann't be more than size
* Return number of written characters
*/
ssize_t fillString(char * buffer, ssize_t size);
Since C++11:
std::string str;
// Resize string to be sure to have memory
str.resize(80);
auto newSize = fillSrting(&str[0], str.size());
str.resize(newSize);
or without first resizing:
std::string str;
if (!str.empty()) // To avoid UB
{
auto newSize = fillSrting(&str[0], str.size());
str.resize(newSize);
}
But before C++11, std::string isn't guaranteed to be stored in a single chunk of contiguous memory. So you have to pass through a std::vector<char> before;
std::vector<char> v;
// Resize string to be sure to have memor
v.resize(80);
ssize_t newSize = fillSrting(&v[0], v.size());
std::string str(v.begin(), v.begin() + newSize);
You can use it easily with something like Daniel's proposition
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:
how to design the set function?
how to design the other functions that use the char* member variable?
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.
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).
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.
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).
The initial problem is that I have some data to save and retrieve from plate and would like to use a helper struct in the following way:
// this is how I want to use my struct for saving
void safeData()
{
Data data;
data.name = getNameToSave(); // returns const char*
save(data);
}
// ... and in the same way for writing.
void readData()
{
Data data;
read(data);
use(data);
}
... whereas
struct Data
{
const char* name;
// potentially many more data members
}
I'm bound to (const) char* instead of std::string for now because this should be used with legacy code. Unfortunately this will bring up a constness problem:
void read(Data& data)
{
// initial legacy free
free(data.name); // warning: can't convert from const char* to void*
// fill with some data
data.name = getNameFromPlate();
}
So the thing is this: Since my data retrieval methods for reading like getNameFromSomewhere returns const char* I'm bound to making my struct members const, too. This however clashes with write-usage because in this case they must be non-const. What is the best and cleanest way to work around this?
The cleanest way is for the Data struct to own the name data. So when you assign to it you should allocate memory and do a memcpy. This is the only way to make sure that a) you don't leak memory b) the data is not freed before you are done with it and c) data is not changed by other processes in the mean time.
Since you do a copy anyway, you can probably make it more manageable by using std::string instead of const char*. When you assign for const char*, std::string will do the copy for you and you can get a const char* back with c_str(), so that you can still work with the legacy architecture. You don't have to do the switch but will make it easier to manage in the long run.
You have not only a problem of constness, but also a problem of ownership. Except if the API states that the return value of getNameToSave() has to be freed by caller after use, you should not free it. While when you read it from a file, you must free it.
So the simpler way is to always use a local copy that you consistently free after use. As you are required to use old const char * instead of std::string you'd better keep using the good old C library function. Here the best function is strdup that automagically allocate memory and copy old string into it.
An alternative way would be to store the status of the member Data::name in a boolean member :
struct Data
{
const char* name;
bool dyn; // must be freed if true
// potentially many more data members
}
You can then safely use:
if (data.dyn && (data.name != nullptr)) {
free(const_cast<char *>(data.name);
}
//In header file: class definition:
class myString
{
public:
myString(void);
myString(const char *str);
myString(const myString &); //copy constructor
~myString(void); //destructor
void swap(myString &from);
private:
char *stringPtr;
int stringLen;
};
//in cpp file, defining them member functions
myString::myString(const char *str)
{
stringLen = strlen(str);
stringPtr = new char[stringLen+1];
strcpy(stringPtr,str);
cout << "constructor with parameter called"<<endl;
}
myString::myString(const myString &str)
{
stringPtr = new char[str.stringLen +1];
strcpy(stringPtr,str.stringPtr);
cout << "copyconstructor"<<endl;
}
void myString::swap(myString &from)
{
myString buffer(from);
int lengthBuffer = from.stringLen;
from = new char[stringLen+1];
from.stringLen = stringLen;
strcpy(from.stringPtr, stringPtr);
stringPtr = new char[lengthBuffer+1];
stringLen = lengthBuffer;
strcpy(stringPtr,buffer.stringPtr);
}
You can't modify a reference. Even if you replace it with a pointer modifying a pointer will not modify an object pointed to. Instead you need to work through the reference - just swap the fields.
void myString::swap(myString &from)
{
std::swap( stringLen, from.stringLen );
std::swap( stringPtr, from.stringPtr );
}
the above is using std::swap() as suggested by user sbi in comments. This is completely equivalent to the following (just for illustration, don't reinvent STL):
void myString::swap(myString &from)
// First remember own length and pointer
const int myOldLen = stringLen;
char* myOldPtr = stringPtr;
// now copy the length and pointer from that other string
stringLen = from.stringLen;
stringPtr = from.stringPtr;
// copy remembered length and pointer to that other string
from.StringLen = myOldLen;
from.StringPtr = myOldPtr;
// done swapping
}
Both will work even when called fro self-swapping:
myString string;
string.swap( string );
You have already gotten a few good answers concerning the errors in you myString::swap() function. Yet, I'd like to add another one. There's some many things wrong with that function, I first found it hard to think of where to begin. But then I realized that you fail on some fundamental issue which I'd like to point out:
As a convention, a function called swap is expected to perform its task
in O(1)
without ever throwing an exception.
(Yes, I know, there are exceptions: std::tr1::array<>::swap(). But those should be very well justified.) Your implementation fails on both accounts. It is O(n) (strcpy) and might throw an exception (new) -- and it does so unnecessarily and without justification.
When you look at myString, you'll see that it only has two pieces of member data, which both are of built-in type. That means swapping two objects of this class is really simple to do while keeping to the conventions mentioned above: just swap the member data. That's as simple as calling std::swap on them:
void myString::swap(myString &from)
{
std::swap(this->stringPtr,from.stringPtr);
std::swap(this->stringLen,from.stringLen);
}
This is will never fail (swapping two pointers and two integers cannot fail), executes in O(1), is very easy to understand (well, once you get a grip on that swapping, anyway; it is an idiomatic form of implementing a class-specific swap function), and consists of two lines of code calling something well-tested in the standard library instead of 8 lines of code doing error-prone (and, in your case, erroneous) manual memory management.
Note 1: Once you've done this, you should specialize std::swap to call your implementation for your class:
namespace std { // only allowed for specializing function templates in the std lib
template<>
inline void std::swap<myString>(myString& lhs, myString& rhs)
{
lhs.swap(rhs);
}
Note 2: The best (simple, exception-safe, and self-assignment-safe) way to implement assignment for your class is to use its swap:
myString& myString::operator=(const myString& rhs)
{
myString tmp(rhs); // invoke copy ctor
this->swap(tmp); // steal data from temp and leave it with our own old data
return *this;
} // tmp will automatically be destroyed and takes our old data with it
from = new char[stringLen+1]; should be from.stringPtr = new char[stringLen+1]; . Also remember to free the previously allocated memory before allocating new one.
Look closely at the line
from = new char[stringLen+1];
It is the same as
from = MyString(new char[stringLen+1]);
so your constructor of MyString get uninitialized array of chars. Then you trying to get the length of the string, but strlen just looping through chars of the string looking for 0 char. As we don't know what content uninitialized array of chars might have, we don't know what length strlen could return. It can even go further than array boundary and crash your program with segfault. But I can say for sure, after that there's not enough space in from.stringPtr to hold the string you want to copy in it.
So, use from.stringPtr = new char[stringLen+1]; or better from = MyString(*this); since you have copy constructor already.