How to store a const char* to a char*? - c++

I have this code that works as expected:
#define MAX_PARAM_NAME_LEN 32
const char* GetName()
{
return "Test text";
}
int main()
{
char name[MAX_PARAM_NAME_LEN];
strcpy(name, GetName());
cout << "result: " << name << endl;
}
If I'd like to store the result to a char * (because some functions within a Frameworks I'm using use only char * as input) without using the strcpy (for practicality and readability of code, and learning too), how could I do? Keeping in const, this works well:
const char* name;
name = GetName();
but I still have const.
Trying to just use char*:
char* name;
name = GetName();
I get invalid conversion from 'const char*' to 'char*'. What's the best habit for this kind of conversion?

The best habit for this kind of conversion is to use std::string throughout your code. Since the framework that you are using takes const char* as its input, you can always pass it the results of c_str() call on your std::string:
std::string GetName() {
return "Test text";
}
int main() {
std::string name = GetName();
int res = external_framework_function(name.c_str());
cout << "result: " << res << " for " << name << endl;
}
A distant second best is using const char* in your code:
const char* name = GetName();
Since the framework that you are using takes const char* you are good here as well.
If you need a non-const pointer, there is no way around copying the string. You can make a function that does it for you, but you would remain responsible for freeing the copies that you get from it:
char* copy(const char* orig) {
char *res = new char[strlen(orig)+1];
strcpy(res, orig);
return res;
}
...
char *name = copy(GetName());
...
delete[] name;

return "Test text"; returns a pointer to a read-only string literal.
If you're using a function that takes a char* as an input, and you have a const char* (such as a read-only string literal), then you ought to supply a deep copy of the string starting at that const char* to such functions.
Else you risk undefined behaviour at runtime if a function attempts to modify a read-only string.
What you currently have is adequate; assuming you can't work with std::string. (If you can work with std::string and all your framework functions take a const char* input, then I'd suggest your refactoring your code to use a std::string, and pass the output of the c_str() method on that string class to your framework functions.)
Finally, if some of your framework functions require a char* then you could always build yourself a small adapter class:
class Adapter
{
public:
Adapter(const& Adapter) = delete; /*don't try to copy me please*/
Adapter& operator=(const Adapter& ) = delete; /*don't try to copy me please*/
Adapter(const char* s) : m_s(::strdup(s))
{
}
~Adapter() /*free memory on destruction*/
{
::free(m_s); /*use free to release strdup memory*/
}
operator char*() /*implicit cast to char* */
{
return m_s;
}
private:
char* m_s;
};
Then for a function void foo(char* c), you can call foo(Adapter("Hello"/*or any const char* */)); and foo can do as it pleases with the char* that's embedded in the anonymous temporary! You could even enhance this class to take a constructor to a char* where in that case only a shallow copy of the pointer is taken (and the destructor doesn't delete the memory).

In C++, the typical way to "drop const" is by using const_cast<>:
char *name = const_cast<char*>(GetName());
This is, of course, frowned upon, ugly and potentially dangerous, since it's really possible that GetName() returns a pointer to something that shouldn't be changed, and then you go and give yourself permission to change it. It's a good way to get very hard to find bugs, in that case.
A workaround is to use a std::string as a temporary holding area; it will mean copying the string but that might be acceptable performance-wise:
std::string s(GetName());
char *name = s.c_str();
This will of course only work if name isn't kept around when s goes out of scope. If that is the case, then you're going to have some form of persistent string storage layer.

You could explicitly cast it. (char*) getName(). But you probably shouldn't. Because the const bit means something like "promise not to change it". So if i have a function void foo(const char* string) I am saiying: "give me a pointer to a string. I won't change it."
And if you declare a variable const char* string = "hello"; You are saying, this string should not be changed. And because you make this promise, the compiler knows, and can make your code more efficient. This is why:
const char* a = "hello";
const char* b = "hello";
(a==b); //is probably true
your compiler knows you won't change a or b so it makes them point to the same address, so it only has to store one "hello" string. If you now go about changing a, b gets also changed, and this is not what you wanted.
So long story short, if you are absolutely sure that the function your calling does not change the string, you can explicitly cast it. (or better, change the function to (const char*) if it's yours).
If your not sure, you will have to make a copy. (Like you are already doing with strcpy()).

Related

Strange output printing char array

human header
class human
{
char name[];
public:
void setName(char nameValue[]);
char* getName();
}
human cpp
void human::setName(char nameValue[])
{
char name[] = "walter";
}
char* human::getName()
{
return name;
}
main cpp
int main()
{
human myHuman;
char name[] = "walter";
myHuman.setName(name);
char* result3 = myHuman.getName();
cout << "My human has a name of " << result3 << endl;
return 0;
}
I assign the string "walter" but when I print it I get "╠╠╠╠╦ß╩d└²╒".
I don't understand which part is wrong. Can you tell me what's wrong with my code?
First and foremost you are assigning nameValue to a variable local to the function setName, which means that the class variable name is still unitialized when you return it in getName, hence the strange output.
The char name[]; declaration is also incorrect, C++ does not allow for variable length arrays or arrays with unspecified bounds unless they are immediately initialized in which case the size will be deduced given the size of the assigned string.
On that note, warnings must have been issued by your compiler, if not, crank them up, or better yet, make it treat warnings as errors, you'll have more robust code.
For the purpose of your assignment you should just go ahead and use pointers, a small problem arises because C++ does not allow for assignment of string literals to char* variables, this is easily fixed if you use const char*, your compiler may allow the former but it is illegal as per C++ rules.
Applying the corrections above, your code should look more like this:
class human
{
const char* name;
public:
void setName(const char *nameValue);
const char* getName();
};
void human::setName(const char *nameValue)
{
name = nameValue;
}
const char* human::getName(){
return name;
}
int main()
{
human myHuman;
const char* name = "walter";
myHuman.setName(name);
const char* result3 = myHuman.getName();
cout << "My human has a name of " << result3 << endl;
return EXIT_SUCCESS;
}

How to overload an in-place and a copying string manipulation functions?

I would like to be able to do the following:
std::cout << str_manip("string to manipulate");
as well as
std::string str;
str_manip(str);
std::cout << str;
For this, I have two functions
#include <string>
// copying
std::string str_manip(std::string str)
{
// manipulate str
return str;
}
// in-place
void str_manip(std::string& str)
{
// manipulate str
}
but they produce the following error:
error: call of overloaded 'str_manip(std::__cxx11::string&)' is ambiguous
How can I overcome this?
The problem is with this call:
std::string str;
str_manip(str);
std::cout << str;
The compiler doesn't know which version of str_manip to call.
You can change your functions to look like this:
#include <string>
// copying
std::string str_manip(const std::string& str)
{
std::string dup = str;
// manipulate dup
return dup;
}
// in-place
void str_manip(std::string& str)
{
// manipulate str
}
Now, the compiler knows that the ambiguous call has to be the function that takes the non-const parameter. You can also be sure that your call that returns a std::string to the << operator isn't modifying your string.
This might be not the thing you are looking for, but for your code
std::cout << str_manip("string to manipulate");
the parameter to str_manip is not a string but const char* (actually an array, but convertible to a char pointer). You can overload based on that.
std::string str_manip(const char* s)
{
std::string str(s); // create str
// manipulate str
return str;
}
However, let's look at the big picture. When you see str_manip in your code, does this mean "change the string" or "make a new string based on the given string"? Do you want to be intentionally ambivalent on the real meaning?
Consider yourself reading your code in 1 year in future. What will you think when you see a call to str_manip - does this mutate its parameter? Does the answer to the previous question depend on context?
The goal in writing code is to make it clear, especially in a multi-paradigm language like C++. So, in my opinion, just don't do overloading that you are thinking about. Instead, make 2 distinct names, like
void frobnicate_str(std::string&) {...}
std::string get_frobnicated_str(std::string) {...}

Design a method or function which returns a valid string

Based on the idea of this entry Is it a good idea to return “ const char * ” from a function?
I thought to extend this with another question I have.
Consider the following code:
#include <string>
#include <cstdio>
const char * GetSomeString()
{
std::string somestlstring;
somestlstring = "Hello World!";
return somestlstring.c_str();
}
int main()
{
const char * tmp = GetSomeString();
printf("%s\n", tmp);
return 0;
}
If I build it with
g++ source.cpp -o executable
and execute that, I get strange symbols displayed. This is because somestlstring is destroyed through the callstack and the pointer you keep after returning became invalid.
My question is: how should I design a method or function that does not have such behaviour without actually declaring additional global variables or potential member functions?
You should drop the whole C mindset and start writing C++:
#include <string>
#include <iostream>
std::string GetSomeString()
{
std::string somestlstring;
somestlstring = "Hello World!";
return somestlstring;
}
int main()
{
std::string tmp = GetSomeString();
std::cout << tmp << std::endl;
return 0;
}
One obvious solution is to make the return type std::string.
how should I design a method or function that does not have such beahviour without actually declaring additional global variables or potential member functions?
Not at all. If you return a const char *, your function is kind of telling the caller "here you have a C string to use, but it stays mine" *), and this implies the caller doesn't have to bother releasing the resources, for example. So you can do this from an instance method (returning a pointer to a field) or you can have a function return a pointer to some static buffer (global variable).
If you want to return a dynamically allocated C string from a function, you must return char * instead and the caller has to free() it when done using it.
That all said, in C++ this doesn't make much sense, except when somehow interfacing with C code. If you want to write C++ code, go with nvoigt's answer.
*) this is thinking in terms of ownership, which is very helpful dealing with manually managed resources. The owner of something is responsible for appropriate cleanup. You can only return a const raw pointer if you don't transfer ownership of the object to the caller.
You are currently referencing the memory of a local std::string object which is destroyed when the object goes out of scope (when returning from the function)
if you really want to return a const char *:
you have to make your std::string static (but only 1 value is shared by your application)
or you have to duplicate the string memory (but you need to free it or you get memory leaks, like happened a lot with the old str() method of the old strstream object, which was later converted to std::string)
But as others said, better stick to C++ std::string (or const reference) as a return value and take c_str() of that returned string when needed for C-style interfaces.
std::string tmp = GetSomeString();
FILE *f = fopen(tmp.c_str(),"r");
The local string variable in the GetSomeString() function will get out of scope after you returned from the funtion. You will be printing random stuff that is in the memory position where the string was before. Try this:
#include <string>
#include <cstdio>
void GetSomeString(std::string& str)
{
str = "Hello World!";
}
int main()
{
std::string str;
GetSomeString(str);
std::cout << str << std::endl;
return 0;
}

C++ char * pointer passing to a function and deleting

I have a the following code:
#include <iostream>
using namespace std;
void func(char * aString)
{
char * tmpStr= new char[100];
cin.getline(tmpStr,100);
delete [] aString;
aString = tmpStr;
}
int main()
{
char * str= new char[100];
cin.getline(str,100);
cout<< str <<endl;
func(str);
cout<< str <<endl;
return 0;
}
Why the second cout does not print the second input string? How can I change this code to work it?
As GregS has said, the simplistic answer is to declare your function using a reference:
void func(char *&aString)
However it is not really the best solution. In C++ you generally avoid simple arrays and use containers.
#include <iostream>
#include <string>
void func(std::string &s)
{
std::getline(std::cin, s);
}
int main()
{
std::string str;
func(str);
std::cout << str << std::endl;
return 0;
}
Because the second cout will print what is pointed by str. And str, the pointer, in your main function will have the same value before and after the call to func.
Indeed, in the func function, you are changing the value of the aString variable. But this is another variable than str in main.
If you want the value of str to be changed, you have to pass it to func by reference or by pointer. (Note that what you write, is to pass the characters by pointer. I mean you have to pass the pointer by pointer: void func(char **str_ptr), or by reference void func(char *&str_ref))
If you're really doing C++, you should use std::string instead of the old C strings.
An example of passing the pointer by pointer:
func(char ** aString)
{
char * tmpStr= new char[100];
cin.getline(tmpStr,100);
delete [] *aString;
*aString = tmpStr;
}
Plus you should call it like this: func(&str);
When func() is called from main() the value of str pointer is passed to the function (this is done by copying it's value to the stack)
The value that was stored on stack when calling func() becomes a local variable aString within func(). You can modify this value but as soon as func() returns all of it's local variables will be discarded. Value of aString won't be copied back to str.
For your code to work you have to either:
Use the buffer pointed to by aString to read data: cin.getline(aString ,100);
or
Pass pointer to pointer: void func(char **aString)
Change func to
void func(char * aString)
{
cin.getline(aString,100);
}
and it works, at least it did for me.
The pointer is passed by value. Yes, you can change the content of what that pointer points to, but the old address itself is preserved when you exit the function. Hence, "aString=tmpStr"; becomes useless and "char * tmpStr= new char[100];" creates a memory leak. You need to pass the pointer by reference:
void func(char*& aString)
{
char * tmpStr= new char[100];
cin.getline(tmpStr,100);
delete [] aString;
aString = tmpStr;
}
If your aim is to actually read a line from the keyboard, do this:
std::string foo;
std::getline(std::cin, foo);
Otherwise, when you pass a pointer to a function, the pointer is passed by value. This means you cannot change the pointer itself from within the function, but you can change the object it points to. In C++ you could do this as follows:
void bar(std::string & s) {
std::getline(std::cin, s);
}
// in calling code
std::string foo;
bar(foo);
This passes a reference to the string to the function. The function can now change the contents of the string.
If you want to write a function that allocates some memory to store a result in, do it like this:
boost::shared_array<char> foo() {
boost::shared_array<char> result(new char[100]);
std::cin.getline(result.get(), 100);
return result;
}
assignment to the parameter aString within the function has no effect on str in main()
you might try
return aString
and in main
str = funct(str);
But in fact there's probably no reason to pass str into the function.
The line aString = tmpStr just changes the value of astring (i.e. an adress/pointer) to another value (i.e. another adress/pointer), but not the content of the momory pointed to by aString.
You could try to change the signature to:
void func(char ** aString)
And changing the last two lines of func to:
delete [] *aString;
*aString = tmpStr;
So the last line causes the program to change the adress stored in the memory pointed to by aString to the adress newly allocated (tmpStr). (I know, it's mind-boggling.)
And then call it via
func(&str);
You need to pass str as a reference.
#include <iostream>
void func(std::istream& is, std::string& aString)
{
std::getline(is, aString);
}
int main()
{
std::string str;
std::getline(std::cin, str);
if(std::cin)
std::cout<< str << '\n';
std::string str;
func(std::cin, str);
if(std::cin)
std::cout<< str << '\n';
return 0;
}
The pointer aString which you pass to func() indicates where (at which address) you can read and write the string str. When you then say aString = tempStr, you're replacing its original value (the address of the string pointed to by str) with a new value (the address of the string pointed to by tempStr). This will not cause str to point to the same place as tempStr.
Imagine I give you a piece of paper with my friend's home address it. Then you scratch it out and write the address of your brother (who lives in London) on it. If I then decide to visit my friend, I won't find myself traveling to London, even though you may have a piece of paper that says "Paul's friend: 123 London".
To get main to print out the string you entered in func(), you can either copy the input string to aString (you move your brother to my friend's house), or pass a pointer or reference to str (have me give you my address book, so you can change the entry for my friend to London). Either way, next time I visit "my friend's house", your brother will be there.

Realloc()/Resize an object in C++ for a string implementation

When they are represented in memory, are C++ objects the same as C structs?
For example, with C, I could do something like this:
struct myObj {
int myInt;
char myVarChar;
};
int main() {
myObj * testObj = (myObj *) malloc(sizeof(int)+5);
testObj->myInt = 3;
strcpy((char*)&testObj->myVarChar, "test");
printf("String: %s", (char *) &testObj->myVarChar);
}
I don't think C++ allows overloading the + operator for the built-in char * type.
So i'd like to create my own lightweight string class which has no extra overhead that std::string has. I think std::string is represented contiguously:
(int)length, (char[])data
I want exactly the same functionality but without prefixing the length (saving 8 bytes overhead).
Here is the code i'm using to test, but it results in a segfault
#include <iostream>
using namespace std;
class pString {
public:
char c;
pString * pString::operator=(const char *);
};
pString * pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
cout << "Address of this->c: " << (uint32_t) &this->c << endl;
realloc(this, strlen(buff)+1);
memcpy(this, buff, strlen(buff));
*(this+strlen(buff)) = '\0';
return this;
};
struct myObj {
int myInt;
char myVarChar;
};
int main() {
pString * myString = (pString *) malloc(sizeof(pString));
*myString = "testing";
cout << "'" << (char *) myString << "'";
}
Edit: nobody really understands what i want to do. Yes i know i can have a pointer to the string in the class but thats 8 bytes more expensive than a plain cstring, i wanted exactly the same internal representation. Thanks for trying though
Edit: The end result of what i wanted to achieve was being able to use the + operator with NO extra memory usage compared to using strcat etc
const char * operator+(const char * first, const char * second);
You should not waste your time writing string classes - there's a reason people spent time writing them in the first place and it's naive to think they wrote them because they wanted to create big obfuscated and overheaded code that you could easily improve in a matter of hours.
For example your code has quadratic complexity for memory reallocations in the assignment operator - each assignment of a sting greater by 1 character will use a new memory block greater by 1 byte resulting in big memory fragmentation after a "few" assignments like this - you save a few bytes but potentialy lose megabytes to address space and memory page fragmentation.
Also designing this way you have no way of efficiently implementing the += operator as instead of just copying the appended string in most cases you will always need to copy the whole string - thus reaching quadratic complexity again in case you append small strings to one bigger one a few times.
Sorry but your idea looks to have great chances of becoming terrible to maintain and orders of magnitude less efficient then the typical string implementations like std::string.
Don't worry - this is true for practicaly all great ideas of "writing your own better version of a standard container" :)
struct myObj {
//...
char myVarChar;
};
This won't work. You either need a fixed size array, a pointer to char or use the struct hack. You won't be able to assign a pointer to this myVarChar.
so i'd like to create my own lightweight string class which has no extra overhead std::string has.
What extra overhead are you referring to? Have you tested and measured to see if std::string is really a bottleneck?
I think std::string is represented contiguously
Yes, mostly, the character buffer part. However, the following:
(int)length(char[])data
is not required by the standard. Translated: A string implementation need not use this particular layout of its data. And it may have additional data.
Now, your lightweight string class is frought with errors:
class pString {
public:
char c; // typically this is implementation detail, should be private
pString * pString::operator=(const char *);
// need ctors, dtors at least as well
// won't you need any functions on strings?
};
Try something along the lines of the following:
/* a light-weight string class */
class lwstring {
public:
lwstring(); // default ctor
lwstring(lwstring const&); // copy ctor
lwstring(char const*); // consume C strings as well
lwstring& operator=(lwstring const&); // assignment
~lwstring(); // dtor
size_t length() const; // string length
bool empty() const; // empty string?
private:
char *_myBuf;
size_t _mySize;
};
Wow. What you're trying to do is a complete abuse of C++, would be totally compiler dependent if it worked, and would surely land you in TheDailyWTF some day.
The reason you're getting a segfault is probably because your operator= is reallocating the object to a different address, but you're not updating the myString pointer in main. I hesitate to even call it an object at this point, since no constructor was ever called.
I think what you're trying to do is make pString a smarter pointer to a string, but you're going about it all wrong. Let me take a crack at it.
#include <iostream>
using namespace std;
class pString {
public:
char * c;
pString & operator=(const char *);
const char * c_str();
};
pString & pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
cout << "Address of this->c: " << (uint32_t) this->c << endl;
c = (char *) malloc(strlen(buff)+1);
memcpy(c, buff, strlen(buff));
*(c+strlen(buff)) = '\0';
return *this;
};
const char * pString::c_str() {
return c;
}
int main() {
pString myString;
myString = "testing";
cout << "'" << myString.c_str() << "'";
}
Now I wouldn't use malloc but new/delete instead, but I left this as close to your original as possible.
You might think you are wasting the space of a pointer in your class, but you aren't - you're trading it for the pointer you previously kept in main. I hope this example makes it clear - the variables are the same size, and the amount of additional memory allocated by malloc/realloc is the same as well.
pString myString;
char * charString;
assert(sizeof(myString) == sizeof(charString));
P.S. I should point out that this code still needs a lot of work, it's full of holes. You need a constructor to initialize the pointer, and a destructor to free it when it's done, just for starters. You can do your own implementation of operator+, too.
You cannot change the size of an object/struct in either C or C++. Their sizes are fixed at compile time.
when they are represented in memory are objects C++ objects the same as C structs.
Strictly speaking, no. In general, yes. C++ classes and structs are identical in memory layout to C structs except:
Bit fields have different packing rules
Sizes are fixed at compile time
If there are any virtual functions, the compiler will add a vtable entry to the memory layout.
If the object inherits a base class, the new class' layout will be appended to the base class layout, including vtable, if any.
I don't think C++ allows overloading the + operator for the built in char * type. so i'd like to create my own lightweight string class which has no extra overhead std::string has. I think std::string is represented contiguously
You can create a operator+ overload for the char* type. Normal behavior is pointer arithmetic. std::string overloads operator+ to append char* data to the string. The string is stored in memory as a C string, plus additional information. The c_str() member function returns a pointer to the internal char array.
In your C example, you're relying on undefined behavior. Don't realloc like that. It can result in Bad Things - namely bizarre segfaults.
Your C++ example is also doing Bad Things in doing realloc(this). Instead, you should carry a char* and get a new char[] buffer to store the chars in instead of a realloc(). Behavior for such a realloc is undefined.
There is a lot a wrong with your class definition/usage. If you want to store a string you should use a pointer type, like char* a member, not an individual char. Using a single char means that only a single character of memory is allocated.
Another mistake is the allocation code where you do a realloc on this - you can potentially change the memory allocated, but not the value of this. You must assign the result to this to achieve this (this = (*pString)realloc(this, strlen(buff+1));) and that is really bad practice anyway. Much better to use realloc on a char* member.
Unfortunately C++ proper has no alternative for realloc or expand and you must instead use new and delete, doing any copying yourself.
Why do you write in C with classes, why don't use C++?
I do not think 'this' works the way you think it works.
Specifically, you cannot reallocate this to point to a larger buffer in a member function, because whatever called that member function still has a pointer to the old 'this'. Since it's not passed by reference there is no way that you can update it.
The obvious way around that is that your class should hold a pointer to the buffer and reallocate that. However, reimplementing a string class is a good way to give yourself lots of headaches down the line. A simple wrapper function would probably accomplish what you wanted (assuming "being able to use the + operator with NO extra memory usage compared to using strcat" is really what you wanted):
void concatenate(std::string& s, const char* c) {
s.reserve(s.size() + strlen(c));
s.append(c);
}
There's some probability that append may do that internally anyway though.
don't mind the lack of const correctness, as this is a mock up, but how about this:
class light_string {
public:
light_string(const char* str) {
size_t length = strlen(str);
char* buffer = new char[sizeof(size_t) + length + 1];
memcpy(buffer, &length, sizeof(size_t));
memcpy(buffer + sizeof(size_t), str, length);
memset(buffer + sizeof(size_t) + length, 0, 1);
m_str = buffer + sizeof(size_t);
}
~light_string() {
char* addr = m_str - sizeof(size_t);
delete [] addr;
}
light_string& operator =(const char* str) {
light_string s = str;
std::swap(*this, s);
return *this;
}
operator const char*() {
return m_str;
}
size_t length() {
return
*reinterpret_cast<size_t *>(m_str - sizeof(size_t));
}
private:
char* m_str;
};
int main(int argc, char* argv[])
{
cout<<sizeof(light_string)<<endl;
return 0;
}
You are moving the "this" pointer. Thats not going to work.
I think what you really want is just a wrapper around a buffer.
#include <iostream>
using namespace std;
class pString {
public:
char c[1];
pString * pString::operator=(const char *);
};
pString * pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
cout << "Address of this->c: " << (uint32_t) &this->c << endl;
realloc(this->c, strlen(buff)+1);
memcpy(this->c, buff, strlen(buff));
*(this->c+strlen(buff)) = '\0';
return this;
};
struct myObj {
int myInt;
char myVarChar;
};
int main() {
pString * myString = (pString *) malloc(sizeof(pString));
*myString = "testing vijay";
cout << "'" << ((char*)myString << "'";
}
This should work. But its not advisable.
#include <iostream>
using namespace std;
class pString {
public:
char c;
pString * pString::operator=(const char *);
};
pString * pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
cout << "Address of this->c: " << (uint32_t) &this->c << endl;
char *newPoint = (char *)realloc(this, strlen(buff)+1);
memcpy(newPoint, buff, strlen(buff));
*((char*)newPoint+strlen(buff)) = '\0';
cout << "Address of this After: " << (uint32_t) newPoint << endl;
return (pString*)newPoint;
};
int main() {
pString * myString = (pString *) malloc(sizeof(pString));
*myString = "testing";
cout << "Address of myString: " << (uint32_t) myString << endl;
cout << "'" << (char *) myString << "'";
}
Works When realloc doesn't re-assign the pointer i.e.
Address of this: 1049008
Address of this->c: 1049008
Address of this After: 1049008
Address of myString: 1049008 'testing'
Works, but when the the following happens it fails
Address of this: 1049008
Address of this->c: 1049008
Address of this After: 1049024
Address of myString: 1049008 ''
the obvious solution is to have
this = (pString*) newPoint;
But the compiler complains about an invalid lvalue in assignment. Does anyone the correct way to update this (just for completeness, i doubt i'll use the code since everyone seems to hate it). Thanks
If you want something that is basically the same as std::string except that it doesn't know how long the string is, you should learn how std::string works, what operator overloads it has, etc. and then mimic that, with just the differences you want.
There is unlikely to be any real point to this, however.
Regarding your latest update - you say you want a design in which general application code will be passing around naked pointers to heap objects. With no automatic cleanup.
This is, quite simply, a very bad idea.
What you want to do doesn't and cannot work in C++. What you are looking for is the C99-feature of flexible arrays. This works nice in C99 for two reasons, first you don't have build-in constructors and second you don't have inheritance (at least not as a language feature). If a class inherits from another the memory used by the subclass is packed by hind the memory of the parent class, but a flexible array needs to be at the end the structure/class.
class pString {
char txt[];
}
class otherString : pString { // This cannot work because now the
size_t len; // the flexible array is not at the
} // end
Take std::string it was written by experts of C++, I'm sure they didn't leaved out a "good trick" without a reason. If you still find out that they don't perform very well in your programm, use plain C strings instead, of course, they don't provide the sweet API, you want.
You can't realloc C++ objects. As others pointed out this is not really a pointer you can modify, there's no guarantee that it will be pointing to an area realloc has access.
One solution to concatenation is to implement a class hierarchy that will defer the real concatenation until it is needed.
Something like this
class MyConcatString;
class MyString {
public:
MyString(const MyConcatString& c) {
reserve(c.l.length()+c.r.lenght());
operator = (l);
operator += (r);
}
MyConcatString operator + (const MyString& r) const {
return MyConcatString(*this, r);
}
};
class MyConcatString {
public:
friend class MyString;
MyConcatString(const MyString& l, const MyString& r):l(l), r(r) {};
...
operator MyString () {
MyString tmp;
tmp.reserve(l.length()+r.length());
tmp = l;
tmp += r;
return tmp;
}
private:
MyString& l;
MyString& r;
}
So if you have
MyString a = "hello";
MyString b = " world";
MyString c = a + b;
Will turn into
MyString c = MyConcatString(a, b);
For more detail check "The C++ Programming language".
Other solution, is to wrap char* inside a struct, but you seem to no like this idea.
But whatever solution you will choose, objects in C++ can't be relocated.
If you want performance, you can write your class like this:
template<int max_size> class MyString
{
public:
size_t size;
char contents[max_size];
public:
MyString(const char* data);
};
Initialize max_size to an appropriate value under context. In this way the object can be created on stack, and no memory allocation is involved.
It is possible to create what you desired by overloading new operator:
class pstring
{
public:
int myInt;
char myVarchar;
void* operator new(size_t size, const char* p);
void operator delete(void* p);
};
void* pstring::operator new(size_t size, const char* p)
{
assert(sizeof(pstring)==size);
char* pm = (char*)malloc(sizeof(int) + strlen(p) +1 );
strcpy(sizeof(int)+pm, p);
*(int*)(pm) = strlen(p); /* assign myInt */
return pm;
}
void pstring::operator delete(void* p)
{
::free(p);
}
pstring* ps = new("test")pstring;
delete ps;
This code is a mess and RnR and others suggested is not advisable. But it works for what i want it to do:
#include <iostream>
using namespace std;
struct pString {
/* No Member Variables, the data is the object */
/* This class cannot be extended & will destroy a vtable */
public:
pString * pString::operator=(const char *);
};
pString& operator+(pString& first, const char *sec) {
int lenFirst;
int lenSec = strlen(sec);
void * newBuff = NULL;
if (&first == NULL)
{
cout << "NULL" << endl;
lenFirst = 0;
newBuff = malloc(sizeof(pString)+lenFirst+lenSec+1);
} else {
lenFirst = strlen((char*)&first);
newBuff= (pString*)realloc(&first, lenFirst+lenSec+1);
}
if (newBuff == NULL)
{
cout << "Realloc Failed"<< endl;
free(&first);
exit(0);
}
memcpy((char*)newBuff+lenFirst, sec, lenSec);
*((char*)newBuff+lenFirst+lenSec) = '\0';
cout << "newBuff: " << (char*)newBuff << endl;
return *(pString*)newBuff;
};
pString * pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
char *newPoint = (char *)realloc(this, strlen(buff)+200);
memcpy(newPoint, buff, strlen(buff));
*((char*)newPoint+strlen(buff)) = '\0';
cout << "Address of this After: " << (uint32_t) newPoint << endl;
return (pString*)newPoint;
};
int main() {
/* This doesn't work that well, there is something going wrong here, but it's just a proof of concept */
cout << "Sizeof: " << sizeof(pString) << endl;
pString * myString = NULL;
//myString = (pString*)malloc(1);
myString = *myString = "testing";
pString& ref = *myString;
//cout << "Address of myString: " << myString << endl;
ref = ref + "test";
ref = ref + "sortofworks" + "another" + "anothers";
printf("FinalString:'%s'", myString);
}