From what I understand, this should work:
const char* x = "x";
std::cout << x << std::endl;
Passing x into this function:
void myClass::passAsVoid(void* v) {
std::cout << (const char*)v << std::endl;
}
The first example prints "x";
The second example prints "\350\224A";
I want to learn what's going on, and the correct approach to do this!
The actual code:
float delay = 1;
std::string txt = "random filler text that is not lorum ipsum";
for (int i = 0; i < txt.length(); ++i) {
const char* x = "x";
std::cout << x << "code1" << std::endl;
CCSequence* seq = CCSequence::create(CCDelayTime::create(i*delay),
CCCallFuncND::create( this, callfuncND_selector(OverWorldView::setString), (void*)x ),
NULL);
this->runAction(seq);
}
Callback function:
void OverWorldView::setString(void* x) {
std::cout << (const char*)x << "code2" << std::endl;
label1->setString( (const char*)x );
}
I'm using cocos2dx 2.1.4
It looks like you are not using the API correctly.
The documentation says you need to use a SEL_CallFuncND type callback, which receives two arguments, not one.
For everyone's convenience, callfuncND_selector is a macro that hides a static_cast, or probably even a C-style cast (could not find other API versions online) which lets you use just about anything as a callback without getting any compilation errors. Pure joy.
This won't even compile because you're passing a const pointer to a function which accepts a non-const pointer. If you can't change the type of the callback then instead of passing a string literal, pass a character array.
char buffer[100];
callback(buffer); //buffer decays to char* which is implicitly converted to void*
If you can change the type of the callback though then modify the parameter to be const void*.
Related
I am trying to store a char* into a struct's char* field. I have tried different things but none of them worked. The problematic piece of code is shown below:
pInfo is the object of the struct PlayerInfo.
PlayerInfo *pInfo = (PlayerInfo*)malloc(sizeof(PlayerInfo));
The char* I get from GetAddress is stored in the Address field of PlayerInfo.
pInfo->Address = GetAddress(pInfo->playerId);
The GetAddress function is shown below. It converts integers to strings, stores them in a vector and returns the vector as a char* using &retChar[0].
char* GetAddress(int playerId)
{
std::string strPlayerId = std::to_string(playerId);
std::string strGroupId = std::to_string(group.GetGroupId());
std::string retAddress = strPlayerId + ":" + strGroupId + ":" + GenRandomChar();
//From -- http://stackoverflow.com/questions/347949/convert-stdstring-to-const-char-or-char
std::vector<char> retChar(retAddress.begin(), retAddress.end());
retChar.push_back('\0');
for(std::vector<char>::const_iterator i = retChar.begin(); i != retChar.end(); ++i)
std::cout << "retChar is " << *i << std::endl;
return &retChar[0];
}
When I print the contents, only garbage is printed. I tried printing the memory contents from gdb, but that also did not help.
char* address = GetAddress(pInfo->playerId);
std::cout << "address is " << *address << std::endl;
std::cout << "address is " << pInfo->Address << std::endl;
std::cout << "address is " << *(pInfo->Address) << std::endl;
The problem is, that your function scope local variable
std::vector<char> retChar;
goes out of scope and is destroyed after your function returned.
Thus using the returned pointer return &retChar[0]; is calling undefined behavior.
The better choice would be to pass the pointer where to copy the data as a reference
void GetAddress(int playerId, char*& result) {
std::vector<char> retChar;
// ...
std::copy(retChar.begin(),result);
}
and ensure result buffer is big enough to receive the copied data.
NOTE:
The above suggestion just solves the 1st level of your current problem. The probably better idea is to change your function simply to deal with std::string instead of using std::vector<char> and raw char* pointers (if your use case allows to refactor this):
Make PlayerInfo::Address member a std::string type
struct PlayerInfo {
// ...
std::string Address;
};
and define your GetAddress() function as follows
std::string GetAddress(int playerId) {
std::ostringstream result;
result << playerId << ":" group.GetGroupId() << ":" << GenRandomChar();
return result.str();
}
and use the results std::string::c_str() method if you really need a const char* value to pass it elsewhere.
I think the idea of using std::vector<char> in the selected answer to How to convert a std::string to const char* or char*? is that the std::vector<char> is your writable character array, not that you should extract a char * from it. (You can, however, copy the contents into a different memory location identified by a char *, as you have already seen.)
But I would ask why you are storing a char * in the Address member of PlayerInfo. Why don't you make that member an std::string and change the return type of getAddress() to std::string, in which case getAddress can simply return retAddress?
Alternatively, you can declare getAddress like this: void getAddress(int playerId, std::string& retAddress) and the code inside the function is even simpler, because you don't have to declare retAddress as a local variable inside the function.
I would like to use parameter in C++ to store back whatever value/object.
In this example, I try to store the value from the global variable as a simplified example.
This code doesn't work,
int value = 20;
void returnPointer2(int* hello)
{
hello = &value;
}
// It changes nothing
int value2 = 100;
returnPointer2(&value2);
cout << value2 << endl;
as I needed double pointer.
void returnPointer3(int** hello)
{
*hello = &value;
}
int* vp2 = new int();
*vp2 = -30;
returnPointer3(&vp2);
cout << *vp2 << endl; // expects 20
I reminded of the reference, and I can use pointer reference to get the same result.
void returnPointer4(int* & hello)
{
cout << "value : " << value;
hello = &value;
}
int* vp3 = new int();
*vp3 = -130;
returnPointer4(vp3); // also expects 20, but much simpler to use
cout << "better : " << *vp3 << endl;
I tried with double &, and it compiles.
void returnPointer5(int&& hello)
{
cout << "value : " << value;
hello = value;
}
However, it doesn't compile with the input of integer variable.
int vp4 = 123;
returnPointer5(vp4); // also expects 20, but even more simpler to use
cout << "best : " << vp4 << endl;
This is an error message.
pointer_return.cpp:31:6: error: initializing argument 1 of 'void returnPointer5(int&&)'
void returnPointer5(int&& hello)
I happened to know about move, and it works with this code.
int vp4 = 123;
returnPointer5(move(vp4)); // also expects 20, but much simpler to see
cout << "best : " << vp4 << endl;
What's the magic/logic behind this move function?
There is a lot of stuff getting mixed in here, but to keep it simple I'll address your root question.
&& is nothing at all like **.
&& is an rvalue reference, while ** is a pointer to a pointer.
As a second point, you are declaring in your function name what you want to do: returnPointer4.
You want to have a pointer to an integer returned back. int*& is the correct syntax for having a reference to a pointer.
Reading over your question again, why don't you use the following:
int& returnGlobalReference() {
return value;
}
Then in your other function:
int& value2 = returnGlobalReference();
The first attempt makes the classic mistake of passing a pointer by value, modifying its address in the function and expecting what it points to to change.
As mentioned in the comments,
void returnPointer2(int* hello)
{
hello = &value; // don't do this, it only modifies what the
// pointer hello, which resides in the stack, points to
*hello = value; // do this instead. even though hello still resides in the
// stack, you're modifying the location that hello points to,
// which was your original intention
}
why do you want to pass pointers however? is the static variable not available when you call the function? (perhaps, different files?)
The magic of std::move is:
The actual declaration for std::move is somewhat more involved, but at its heart, it's just a static_cast to an rvalue reference.
Taken from here.
As Jeffery Thomas already said, a && is not a reference to a reference, but a reference to a rvalue.
im having an issue with the ostream, I have written a very basic macro that should print out its parameters.
Please see example code below:
#define LOG Message(__FILE__, __LINE__,__func__)
class Message : public std::ostringstream
{
public:
Message(const char *param1, int param2, const char *param3)
{
*this<<param3<<"("<<param1<<":"<<param2<<")";
}
~Message()
{
*this<<endl;
cout<< rdbuf()->str();
}
};
int main()
{
int integer = 1;
string str = "XYZ";
LOG<<integer<<"DEBUGLOG1: "<<str<<" "<<integer;
return 0;
}
The problem is if I use:
LOG << "LOG1: " << str << " " << integer;
The output prints the Address* of the const char* "LOG1: " rather than the value.
But,
If I use:
LOG << integer << "DEBUGLOG1: " << str << " " << integer;
The output works perfect, printing the integer value and the char value.
it looks like instead of using ostream& operator<< (ostream& out, const char* s );
it is using ostream& operator<< (const void* val); ?
Can anyone shed any light on what can be done to overcome this overloading please?
Thanks in advance
The problem is that Message(...) is a temporary. The temporary cannot bind to a non-const reference parameter for operator<<.
It can only be used with member functions and operators, like ostream::operator<<(int).
The odd thing is that the member operator returns a reference which can, in turn, be used with the non-member operators.
Precompile and see what the macro is getting unraveled as. Working with macros is difficult (and unadvisable...) and this is a very essentially debugging method you'll need to know to avoid keep reaching for Google or SO.
I believe you want g++ -E.
I have the following code :
#include <cstdarg>
#include <iostream>
using namespace std;
class a {
};
void fun1(a& aa, ...)
{
va_list argp;
va_start(argp, aa);
char *p = 0;
while ((p = va_arg(argp, char *)) != 0) {
cout << p << endl;
}
va_end(argp);
}
void fun2(char *aa, ...)
{
va_list argp;
va_start(argp, aa);
char *p = 0;
while ((p = va_arg(argp, char *)) != 0) {
cout << p << endl;
}
va_end(argp);
}
int main()
{
cout << "fun2" << endl;
fun2("a", "1", "2", (char *)0);
cout << "fun1" << endl;
fun1(a(), "1", "2", (char *)0);
getchar();
}
Everything works fine with fun2. However, fun1 will just crash.
May I know how can I prevent from crashing, at the same time able to use class reference as 1st parameter.
Currently, it prints :
fun2
1
2
fun1
then crash.
I wish
fun2
1
2
fun1
1
2
You can't use a reference parameter as the last named parameter with va_start. The reason is because va_start takes the address of the named parameter to find the location of the rest of the arguments. However, taking the address of a reference gives the address of the variable pointed at by the reference, not the address of the parameter itself. Your options are:
1) change the variable type from a reference to a pointer (or a non-reference if you are OK with a copy of the passed in variable).
2) Add an additional required parameter so that the reference isn't the last named parameter. The additional parameter can be a useful parameter, such as one of the char* you are going to pass to your particular function, or it can be a dummy variable you just ignore.
3) Change the definition of va_start. It's not recommended, but you can do it. See http://support.microsoft.com/kb/119394 for a non-portable redefinition.
It looks to me like you're crashing in fun2.
Because you're calling va_arg too many times and screwing up the stack.
You must only call va_arg the same number of times as there are parameters.
Both fun1 and fun2 terminate the loop when they encounter a NULL or 0 parameter. You are never passing one. Change main to:
int main()
{
cout << "fun2" << endl;
fun2("a", "1", "2", NULL);
cout << "fun1" << endl;
fun1(a(), "1", "2", NULL);
getchar();
return 0;
}
Note I haven't compiled this, but it should work. You may have to follow janm's advice as well.
Update: I set down and thought about this again. You have to either:
Instantiate an object of type a inside of main and pass it or...
Following janm's advice and change a& aa in fun2 to a const& aa
When I tried to compile the original under g++, I was greeted with the following error:
error: invalid initialization of non-const reference of type 'a&' from a
temporary of type 'a'
error: in passing argument 1 of 'void fun1(a&, ...)'
Essentially, you cannot pass a temporary variable as a non-const reference. See this SO question and this Herb Sutter GotW for some of the gory details.
I'm sorry to hear this code doesnt work. I notice if fun2(aa is a ptr instead of a ref the code works. I also notice while trying to compile on gcc (via http://codepad.org/) you pass "a" into fun2 which is a char*. codepad/gcc complained about it not being a const char*. In codepad this code works. In my copy of VS2008 it crashes and 2010b2 as well.
My recommendation is to avoid va params but i'll assume you can't so i suggest not to use ref and use pointers. Or switch to gcc but i wouldnt do that unless there are no other (reasonable) option.
#include<cstdlib>
#include <cstdio>
#include <ios>
#include <iostream>
using namespace std;
class a {
};
void fun1(a& aa, ...)
{
//cout<< "sizeof" << sizeof(aa) << "&aa == " << &aa;
va_list argp;
va_start(argp, aa);
char *p = 0;
while ((p = va_arg(argp, char *)) != 0) {
cout << p << endl;
}
va_end(argp);
}
void fun2(const char *aa, ...)
{
va_list argp;
va_start(argp, aa);
char *p = 0;
while ((p = va_arg(argp, char *)) != 0) {
cout << p << endl;
}
va_end(argp);
}
int main()
{
cout << "fun2" << endl;
fun2("a", "1", "2", 0);
cout << "fun1" << endl;
a aa;
//cout<< "sizeof" << sizeof(aa) << "&aa == " << &aa;
fun1(aa, "1", "2", 0);
getchar();
}
You are passing a non-const reference to a temporary. Change the fun1 prototype to:
void fun1(a const& aa, ...)
Update:
Haven't used varargs for a long time, missed that a terminating parameter wasn't being passed. See D. Shawley's answer; you must pass a terminating parameter if you're going to use that as your interface.
void outputString(const string &ss) {
cout << "outputString(const string& ) " + ss << endl;
}
void outputString(const string ss) {
cout << "outputString(const string ) " + ss << endl;
}
int main(void) {
//! outputString("ambigiousmethod");
const string constStr = "ambigiousmethod2";
//! outputString(constStr);
} ///:~
How to make distinct call?
EDIT: This piece of code could be compiled with g++ and MSVC.
thanks.
C++ does not allow you to overload functions where the only difference in the function signature is that one takes an object and another takes reference to an object. So something like:
void foo(int);
and
void foo(int&);
is not allowed.
You need to change the number and/or the type of the parameter.
In your case the function that accepts a reference, you can make it accept a pointer, if you want to allow the function to change its argument.
You could change the signature of one of the methods. It may not look pretty, however it is the simplest way.
So you could in principle have
void outputString(const string &ss, int notneeded) {
cout << "outputString(const string& ) " + ss << endl;
}
void outputString(const string ss) {
cout << "outputString(const string ) " + ss << endl;
}
and when you want to call the first function just call it with:
outputString("ambigiousmethod", 0);
which will result in a distinguishing call.
There is no other way (I'd love to be proven wrong on this one) since C++ does not allow overloading where passing (by value or by reference) is the only difference in signature.
Edit: as pointed out by bzabhi, you could also change the signature by changing the reference to a pointer. In the example you gave that would work, however you may have to change function code on some occasions.
According to your code, u need only
void outputString(const string &ss).
Because both methods cannot change the argument to the caller (because it's const reference or by-value passing).
Why do you need those 2 methods?
I recommend using the techinque of giving each and every function a unique name., i.e., do not use syntax overloading. I have been using it for years and I've only found advantages in it.