Void * type tracking nightmare!!!

G

Gordon Jahn

Hi all,

I'm trying to define a class that I can dump several known types into
and it will track what was dropped in and provide methods to get the
data back again. Anwyay, after 3 days, I'm branching out for advice!
Included below is my full SettingsManagerSetting class and a main()
which instantiates two instances of it. The problem is that the char
designator is valid only during the constructor phase, which is weird
because it's a member variable being called by value (I think). The
cout's will show that when the class is accessed from the main() again,
the designator data has become garbage.

Does anyone know why on earth this would happen, or more importantly,
how I can make the class actually store data?

I've tried this on both Linux and Windows with GCC (g++) 3.2 and 3.3.1
respectively with the same results, so I reckon it's something I'm doing.

Cheers in advance,
Gordon Jahn

#include <string>
#include <sstream>
#include <iostream>

using namespace std;

class SettingsManagerSetting {
char designator;
void *value;

public:
SettingsManagerSetting(string value) { SettingsManagerSetting(&value,
(char) 'S');};
SettingsManagerSetting(int value) { SettingsManagerSetting(&value,
(char) 'I');};
SettingsManagerSetting(float value) { SettingsManagerSetting(&value,
(char) 'F');};

string getStringValue();
int getIntValue();
float getFloatValue();
char getDesignator() { return designator; };
void printString();
protected:
SettingsManagerSetting(void *newValue, char typeDesignator) {
value = newValue;
designator = typeDesignator;
cout << "SMS: " << getStringValue() << "\n";
};
void *getValue() { return value; };
};

string SettingsManagerSetting::getStringValue() {
cout << "Running getSV, designator: " << getDesignator() << "\n";
switch (getDesignator()) {
case 'S': {
cout << "Howdy... we're in S.\n";
string response = *((string *) getValue());
return response;
}
case 'F': {
cout << "Howdy... we're in F.\n";
stringstream tempstring;
tempstring << getFloatValue();
return tempstring.str();
}
case 'I': {
cout << "Howdy... we're in I.\n";
stringstream tempstring;
tempstring << getIntValue();
return tempstring.str();
}
default: {
return string("I dunno... - couldn't resolve type");
}
}
}

int SettingsManagerSetting::getIntValue() {
int response = *((int *) getValue());
return response;
}

float SettingsManagerSetting::getFloatValue() {
float response = *((float *) getValue());
return response;
}

void SettingsManagerSetting::printString() {
cout << getStringValue() << "\n";
}

int main(int argc, char *argv[]) {
if (argc == 2) {
string ava("a");
int bva = 10;

SettingsManagerSetting *bv = new SettingsManagerSetting(bva);
bv->printString();
cout << "Main: " << (*bv).getStringValue() << "\n";

SettingsManagerSetting *av = new SettingsManagerSetting(ava);
cout << "Main: " << (*av).getStringValue() << "\n";
} else {
cout << "Usage: SettingManager [LookupValue]\n";
}

return 0;
}
 
V

Victor Bazarov

Gordon Jahn said:
I'm trying to define a class that I can dump several known types into
and it will track what was dropped in and provide methods to get the
data back again. Anwyay, after 3 days, I'm branching out for advice!
Included below is my full SettingsManagerSetting class and a main()
which instantiates two instances of it. The problem is that the char
designator is valid only during the constructor phase, which is weird
because it's a member variable being called by value (I think). The
cout's will show that when the class is accessed from the main() again,
the designator data has become garbage.

Does anyone know why on earth this would happen, or more importantly,
how I can make the class actually store data?

There are so many mistakes in your code that you should think about
it a bit more and then rewrite it anew.
I've tried this on both Linux and Windows with GCC (g++) 3.2 and 3.3.1
respectively with the same results, so I reckon it's something I'm doing.

You bet.
Cheers in advance,
Gordon Jahn

#include <string>
#include <sstream>
#include <iostream>

using namespace std;

class SettingsManagerSetting {
char designator;
void *value;

public:
SettingsManagerSetting(string value) { SettingsManagerSetting(&value,
(char) 'S');};

Passing 'string' by value (no pun intended) is a bad idea. Pass by
a const reference.

You cannot call another constructor like you are trying. The syntax
you use creates (and immediately destroys) a temporary object, which
of course doesn't do anything for this one, and 'value' and the type
are immediately lost.

'S' is already of type 'char', no need to cast.

The only time when a semicolon after a closing curly brace is really
necessary is after a class definition.

See? I bet you used Java too much. You got brain-washed by that
language and need to free your mind from their nonsense.
SettingsManagerSetting(int value) { SettingsManagerSetting(&value,
(char) 'I');};
SettingsManagerSetting(float value) { SettingsManagerSetting(&value,
(char) 'F');};

string getStringValue();

Those member functions should be 'const'.
int getIntValue();
float getFloatValue();
char getDesignator() { return designator; };

Why do you feel that you need this?
void printString();
protected:
SettingsManagerSetting(void *newValue, char typeDesignator) {
value = newValue;

Even if you didn't write this function up as a constructor, it still
would be a BAD IDEA(tm). You need to maintain your own object instead
of copying the address of a temporary variable. And you should do it
in each of the parameterised constructors instead of the common function
where you pass a void*.
designator = typeDesignator;
cout << "SMS: " << getStringValue() << "\n";
};
void *getValue() { return value; };
};

string SettingsManagerSetting::getStringValue() {
cout << "Running getSV, designator: " << getDesignator() << "\n";
switch (getDesignator()) {
case 'S': {
cout << "Howdy... we're in S.\n";
string response = *((string *) getValue());
return response;
}
case 'F': {
cout << "Howdy... we're in F.\n";
stringstream tempstring;
tempstring << getFloatValue();
return tempstring.str();
}
case 'I': {
cout << "Howdy... we're in I.\n";
stringstream tempstring;
tempstring << getIntValue();
return tempstring.str();
}
default: {
return string("I dunno... - couldn't resolve type");
}
}
}

int SettingsManagerSetting::getIntValue() {
int response = *((int *) getValue());

Bad idea. If your 'value' is a string or a float, what do you get?
Undefined behaviour, that's what. Nasal demons.
return response;
}

float SettingsManagerSetting::getFloatValue() {
float response = *((float *) getValue());

Bad idea. See above.
return response;
}

void SettingsManagerSetting::printString() {
cout << getStringValue() << "\n";
}

int main(int argc, char *argv[]) {
if (argc == 2) {
string ava("a");
int bva = 10;

SettingsManagerSetting *bv = new SettingsManagerSetting(bva);
bv->printString();
cout << "Main: " << (*bv).getStringValue() << "\n";

SettingsManagerSetting *av = new SettingsManagerSetting(ava);
cout << "Main: " << (*av).getStringValue() << "\n";
} else {
cout << "Usage: SettingManager [LookupValue]\n";
}

return 0;
}

V
 
G

Gianni Mariani

Gordon said:
Hi all,

I'm trying to define a class that I can dump several known types into
and it will track what was dropped in and provide methods to get the
data back again. Anwyay, after 3 days, I'm branching out for advice!


There is a much simpler way to do what you're trying to do below - look
at boost::any.

Included below is my full SettingsManagerSetting class and a main()
which instantiates two instances of it. The problem is that the char
designator is valid only during the constructor phase, which is weird
because it's a member variable being called by value (I think). The
cout's will show that when the class is accessed from the main() again,
the designator data has become garbage.

Does anyone know why on earth this would happen, or more importantly,
how I can make the class actually store data?

I've tried this on both Linux and Windows with GCC (g++) 3.2 and 3.3.1
respectively with the same results, so I reckon it's something I'm doing.

Cheers in advance,
Gordon Jahn

#include <string>
#include <sstream>
#include <iostream>

using namespace std;

class SettingsManagerSetting {
char designator;
void *value;

public:

Each of these constructors below - create a temporary
SettingsManagerSetting object and the designator and value settings are
never set in THIS object.
SettingsManagerSetting(string value) {
SettingsManagerSetting(&value, (char) 'S');};
don't need the (char) typecasts.
SettingsManagerSetting(int value) {
SettingsManagerSetting(&value, (char) 'I');};
SettingsManagerSetting(float value) {
SettingsManagerSetting(&value, (char) 'F');};

string getStringValue();
int getIntValue();
float getFloatValue();
char getDesignator() { return designator; };
void printString();
protected:

This below is another constructor ...
SettingsManagerSetting(void *newValue, char typeDesignator) {

What is the lifetime of *newValue. How do you manage when the object
that newValue is pointing is destroyed ? Well, the objects you point to
here are parameters which are temporary copies of the objects you passed
in - no wonder their value vanishes after the constructor is called.
value = newValue;
designator = typeDesignator;
cout << "SMS: " << getStringValue() << "\n";
};

Don't the the ';' in the line above or below - in fact no function
requires a ';' at the end of the declaration.
void *getValue() { return value; };
};

string SettingsManagerSetting::getStringValue() {
cout << "Running getSV, designator: " << getDesignator() << "\n";
switch (getDesignator()) {
case 'S': {
cout << "Howdy... we're in S.\n";
string response = *((string *) getValue());
return response;
}
case 'F': {
cout << "Howdy... we're in F.\n";
stringstream tempstring;
tempstring << getFloatValue();
return tempstring.str();
}
case 'I': {
cout << "Howdy... we're in I.\n";
stringstream tempstring;
tempstring << getIntValue();
return tempstring.str();
}
default: {
return string("I dunno... - couldn't resolve type");
}
}
}

int SettingsManagerSetting::getIntValue() {
int response = *((int *) getValue());
return response;
}

float SettingsManagerSetting::getFloatValue() {
float response = *((float *) getValue());
return response;
}

void SettingsManagerSetting::printString() {
cout << getStringValue() << "\n";
}

int main(int argc, char *argv[]) {
if (argc == 2) {
string ava("a");
int bva = 10;

SettingsManagerSetting *bv = new SettingsManagerSetting(bva);
bv->printString();
cout << "Main: " << (*bv).getStringValue() << "\n";

SettingsManagerSetting *av = new SettingsManagerSetting(ava);
cout << "Main: " << (*av).getStringValue() << "\n";
} else {
cout << "Usage: SettingManager [LookupValue]\n";
}

return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,139
Latest member
JamaalCald
Top