Sign in to follow this  
dsmurl

trouble with vase class pointers

Recommended Posts

I'm just trying to create a checked strcpy wrapper at the moment. IF you run this code you will notice that the values change and reallocate inside the Set_String function but there is no change outside the scope of the function. If you can let me know how to do this, you are a better man than I. - Sam Edit: please use [source lang="cpp"] [source] tags to display large portions of source code (> 10 lines) - Emmanuel
/////////////////////  Immulated child class h and cpp file
class Childer
{
public:
	Childer();
	~Childer() {};

	char* Ctype;

public: int Set_String(char* Destination, char* Source);
};

Childer::Childer()
{
	Ctype = NULL;

	Set_String(Ctype, "Init");	
};

int Childer::Set_String(char* Destination, char* Source)
{
	if (Source == NULL) return -1;  // Nothing to copy

	if (strlen(Source) > 99) return -1;  // Don't copy large strings

	// delete, reallocate, and populate destination pointer
	delete(Destination);
	Destination = new char[strlen(Source) + 1]; 
	strcpy(Destination, Source);

	return 1;
};





/////////////////////  Main
int main(int argc, char* argv[])
{
	Childer* myChild = new Childer();

	char* Error_Message = NULL;

	myChild->Set_String(Error_Message, "Okay");

	if (Error_Message == NULL) printf("Why is Error_Message this still NULL???\n");

	delete [] Error_Message;

	return 0;
}
[Edited by - Emmanuel Deloget on March 20, 2007 5:27:37 AM]

Share this post


Link to post
Share on other sites
The reason for this is that you pass in a COPY of the Error_Message pointer to the function. This new pointer merely points to the same data, but is a whole different variable. Hence, when you do "delete" and "new," on it, it is this COPY that gets deleted and reallocated not your original pointer you passed in; hence when the function ends, this copy gets lost and your old pointer is still the same.

to fix this, pass a pointer to your pointer and change it like this:


#include <cstdlib>
#include <iostream>

using namespace std;

///////////////////// Immulated child class h and cpp file
class Childer
{
public:
Childer();
~Childer() {};

char* Ctype;

public: int Set_String(char** Destination, char* Source);
};

Childer::Childer()
{
Ctype = NULL;

Set_String(&Ctype, "Init");
};

int Childer::Set_String(char** Destination, char* Source)
{
if (Source == NULL) return -1; // Nothing to copy

if (strlen(Source) > 99) return -1; // Don't copy large strings

// delete, reallocate, and populate destination pointer
if((*Destination) != NULL)
delete((*Destination));

(*Destination) = new char[strlen(Source) + 1];
strcpy((*Destination), Source);

return 1;
};





///////////////////// Main
int main(int argc, char* argv[])
{
Childer* myChild = new Childer();

char* Error_Message = NULL;

myChild->Set_String(&Error_Message, "Okay");

if (Error_Message == NULL) printf("Why is Error_Message this still NULL???\n");

delete [] Error_Message;

return 0;
}




Alternatively, you could also use a reference.

Also please note that I also changed it so that the Destination pointer does not get deleted only if it is not null (afaik, deleting null pointers may have some bad side effects, correct me if wrong).

Share this post


Link to post
Share on other sites
Quote:
Original post by Koobazaur
Also please note that I also changed it so that the Destination pointer does not get deleted only if it is not null (afaik, deleting null pointers may have some bad side effects, correct me if wrong).

Quote:
C++ Standard, Section 3.7.3.2, Paragraph 3
The value of the first parameter supplied to a deallocation function shall be a null pointer value, or refer to storage allocated by the corresponding allocation function (even if that allocation function was called with a zero argument). If the value of the first argument is a null pointer value, the call to the deallocation function has no effect. If the value of the first argument refers to a pointer already deallocated, the effect is undefined.


OP: I don't have time right now to go into the various issues with your code, but if this is for anything other than learning purposes, use std::string.

Σnigma

Share this post


Link to post
Share on other sites
I can't use std::string. I have to use normal c strings because I don't want to deal with a lot of string conversions to integrate my code with my friends. Plus, I will make a swap to TCHAR soon. That is why I use char* now.

- Sam

Share this post


Link to post
Share on other sites
Quote:
Original post by dsmurl
I can't use std::string. I have to use normal c strings because I don't want to deal with a lot of string conversions to integrate my code with my friends. Plus, I will make a swap to TCHAR soon. That is why I use char* now.

- Sam

Trust me, string conversions are much, much easier to deal with than c-strings. I second the motion to switch to std::string.

If you insist on it, I would try Koobazaur's advice, and post back with results.

Share this post


Link to post
Share on other sites
Quote:
Original post by dsmurl
I can't use std::string. I have to use normal c strings because I don't want to deal with a lot of string conversions to integrate my code with my friends. Plus, I will make a swap to TCHAR soon. That is why I use char* now.

- Sam


Just so you know, you can call string::c_str() function for a string variable that will return a char* type of a string, so integration shouldn't be a problem.

Share this post


Link to post
Share on other sites
Quote:
Original post by dsmurl
I can't use std::string. I have to use normal c strings because I don't want to deal with a lot of string conversions to integrate my code with my friends. Plus, I will make a swap to TCHAR soon. That is why I use char* now.

- Sam


I will add my voice to the std::string supporters. Realize that you wouldn't even have posted this thread if you were using the standard string class.

Also, using a TCHAR is not an excuse for not using std::string, you can do somthing like the following:

typedef std::basic_string< TCHAR > tstring;, and poof, you have a string based on a TCHAR.

Beyond that, I don't recommend using TCHAR at all. You would be better off choosing narrow or wide strings and sticking with it (in fact, Windows converts narrow strings into wide strings in its system calls, as far as I know).


jfl.

Share this post


Link to post
Share on other sites
Quote:
Original post by Koobazaur
Also please note that I also changed it so that the Destination pointer does not get deleted only if it is not null (afaik, deleting null pointers may have some bad side effects, correct me if wrong).


Deleting a null pointer is a no-op, so it's safe (assuming it is the standard delete):

Quote:
Working Draft, Standard for Programming Language C++ (c2006)
3.7.3.2 Deallocation functions [basic.stc.dynamic.deallocation]
The value of the first argument supplied to a deallocation functions may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect.

Share this post


Link to post
Share on other sites
That sounds good to me. I will look into the std::string implementation more. I have a large class that manages the passing around multiple sets of parameters for a multitude of video encoders. There are hundreds of parameters and it will take a while, so I will do it later. I like the idea of avoiding TCHAR also. I have been getting some cross platform problems with them. Thanks for your advice. One last question, are the std::string dynamically managed in the background or wilol I have to do any allocation myself. The point of the function I'm writing is to abstract the allocation and is the same string as in string.h? Thanks

- Sam

Share this post


Link to post
Share on other sites
Quote:
Original post by dsmurl
One last question, are the std::string dynamically managed in the background or wilol I have to do any allocation myself. The point of the function I'm writing is to abstract the allocation and is the same string as in string.h? Thanks


std::string will do all the allocation and deallocation work you would expect, and probably more - which is exactly why you would want to use it.

In particular, std::string implementations commonly optimize short strings by adding a small char[] to the data struct, and swapping between that and a dynamic allocation depending on what is needed. (IIRC, Microsoft's implementation uses a 'discriminated union' of a local char[] and a dynamic-allocation pointer. Another way it *could* be implemented is to have a local char[] and a pointer, and point the pointer at the buffer when the buffer is being used - and of course also check in the destructor whether it's the buffer being pointed at ;).) It can be done in a few different ways, but the point is that it is

- written by very smart people,
- specifically designed for your compilation environment, to try to be optimized in normal cases,
- for the explicit purpose of saving you from having to do it yourself.

As for string.h - there *is no* 'string' in string.h, which *isn't a C++ header anyway*. It is a C header. If you want its functionality in C++, you should be including <cstring> instead.

That header includes free functions that are designed to help with treating char*'s and char[]'s as if they were strings. This is risky stuff, because of the lack of encapsulation - i.e. you're responsible for all that memory management, and the memory management work tends to get scattered all over the code.

The <string> header (no .h and no c) defines the std::string, which is an actual *data type* (i.e., a class). Some char* and/or char[] is logically associated with each object of the class, in such a way that you can't lose track of it. The std::string "knows" the size of the string (both the length of the allocated memory if any, and the length of the actual string), because that's counted in a separate data member (the standard doesn't specify that, but it's the only realistic way to implement it in a way the provides all the guarantees that *are* specified). As a result, the string is also freed up to contain '\0' characters. Plus, many algorithms will run faster (or at least, can be written "the fast way" easily, instead of requiring careful attention from the programmer) because the program won't be constantly recalculating string lengths that should be "known".

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this