C++/CX: Why doesn't returning a StringReference work like passing one as an argument? - string

Platform::StringReference exists so that you can pass a const wchar_t* across the ABI boundary to a function accepting a String^ without making a copy. The StringReference implicitly converts to a String^ whose internal pointer matches the original const wchar_t*. This is verified by the following code; if you step through it you find that pz == z:
void param(String^ s)
{
const wchar_t* z = s->Data();
}
App::App()
{
std::wstring p = L"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
const wchar_t* pz = p.c_str();
param(StringReference(pz));
}
However, trying to return a StringReference doesn't seem to work the same way and I'm curious why. If I have a function that returns String^ and I return a StringReference from it then the same implicit conversion operator is called, but when the caller gets their String^ it has a different internal data pointer that contains a copy. Here's some code that tries it:
String^ ret()
{
std::wstring s = L"12345678901234567890123456789012345678901234567890";
const wchar_t* z = s.c_str();
return StringReference(z);
}
App::App()
{
String^ r = ret();
const wchar_t* rz = r->Data();
}
That code verifies in two ways: first, if you step through you'll find that z != rz and second, r ends up pointing to a valid string rather than garbage, so a copy must have been made because the original string is freed at the end of ret.
I also tried returning via out parameter, but I get the same results as a straight return (z != oz and o ends up with a valid string):
void out(String^* r)
{
std::wstring s = L"12345678901234567890123456789012345678901234567890";
const wchar_t* z = s.c_str();
*r = StringReference(z);
}
App::App()
{
String^ o;
out(&o);
const wchar_t* oz = o->Data();
}
Is there a way to return a StringReference across the ABI boundary in the same way that you can pass one? I imagine the behavior would depend on the language of the caller and how that language marshals strings from WinRT, but it seems like at least a C++/CX caller ought to be able to do it.

No you can't return a StringReference across the ABI boundary. Returning a StringReference across the ABI boundary is similar (but not identical) to returning the address of a local variable. That's because the whole point of a StringReference is that the StringReference doesn't allocate any new memory.
Consider what would happen if you could return a StringReference across the ABI boundary. What would happen if you had:
String^ ReturnAString()
{
const wchar_t buffer[500] = "MyString";
return StringReference(buffer);
}
The StringReference is just a wrapper around the stack allocated buffer. And clearly you can't return that across the ABI boundary (the stack storage is reclaimed as soon as the routine exits).
Instead you need to return a real Platform::String - a Platform::String contains a copy of the string data and thus it can safely be returned to the caller.

Related

How can I understand this code (string as a function parameter in c)

I have written this code but its not working but when I replace *targ and *sour by targ[] and sour[] then its working. Also it shows many error when I call the function converge like this converge(*targ, *sour). Please someone help me to understand this.
#include<stdio.h>
#include<string.h>
void converge(char *target, char *src);
int main()
{
char *targ = "xxxxxxxxxxxxxxxxxxx";
char *sour = "yyyyyyyyyyyyyyyyyyy";
converge(targ, sour);
//printf("%s", targ);
}
void converge(char *target, char *src)
{
int i, j;
for(i=0,j=strlen(src); i<=j; i++, j--)
{
target[i]= src[i];
target[j]= src[j];
printf("%s\n",target);
}
}
If you define a string like this:
char *targ = "abcd";
it is treated as read-only value, since the string "abcd" is stored in read-only memory, while the pointer targ is stored on your stack. Depending on your compiler you might get some warning unless you make this more explicit with const char *targ = "abcd";. An assignment like targ[i] = src[i]; is not allowed in this case.
If you define a string like this:
char targ[] = "abcd";
a char-array will be created on your data stack, this string can be changed, since data on your stack is readable and writable. Additionally you can access the first element of your array as pointer.

Should I use ReleaseStringUTFChars if I want to return the C sting obtained from GetStringUTFChars?

jstring result = NULL;
**const char *nativeString = NULL;**
if (messageMe != NULL) {
jstring jstrBuf = (envLocal)->NewStringUTF(value);
result = (jstring) envLocal->CallStaticObjectMethod(g_clazz, messageMe,
jstrBuf);
**nativeString = envLocal->GetStringUTFChars(result, 0);**
g_JavaVM->DetachCurrentThread();
return nativeString;
Hi as shown in above example code I am filling nativeString using GetStringUTFChars. my need is to return this nativeString to call to another native calling function.
Must I use ReleaseStringUTFChars(). If I use it then won't it free the memory and nativeString value for the calling function will be invalid.???
I am not getting this answer clearly in other stack overflow questions. please help.
GetStringUTFChars will allocate memory for the string it returns, and ReleaseStringUTFChars frees that memory. So you should call ReleaseStringUTFChars when you're done using the data that GetStringUTFChars returned.

C++ : Strings, Structures and Access Violation Writing Locations

I'm attempting to try and use a string input from a method and set that to a variable of a structure, which i then place in a linked list. I didn't include, all of code but I did post constructor and all that good stuff. Now the code is breaking at the lines
node->title = newTitle;
node->isbn = newISBN;
So newTitle is the string input from the method that I'm trying to set to the title variable of the Book structure of the variable node. Now, I'm assuming this has to do with a issue with pointers and trying to set data to them, but I can't figure out a fix/alternative.
Also, I tried using
strcpy(node->title, newTitle)
But that had an issue with converting the string into a list of chars because strcpy only uses a list of characters. Also tried a few other things, but none seemed to pan out, help with an explanation would be appreciated.
struct Book
{
string title;
string isbn;
struct Book * next;
};
//class LinkedList will contains a linked list of books
class LinkedList
{
private:
Book * head;
public:
LinkedList();
~LinkedList();
bool addElement(string title, string isbn);
bool removeElement(string isbn);
void printList();
};
//Constructor
//It sets head to be NULL to create an empty linked list
LinkedList::LinkedList()
{
head = NULL;
}
//Description: Adds an element to the link in alphabetical order, unless book with
same title then discards
// Returns true if added, false otherwise
bool LinkedList::addElement(string newTitle, string newISBN)
{
struct Book *temp;
struct Book *lastEntry = NULL;
temp = head;
if (temp==NULL) //If the list is empty, sets data to first entry
{
struct Book *node;
node = (Book*) malloc(sizeof(Book));
node->title = newTitle;
node->isbn = newISBN;
head = node;
}
while (temp!=NULL)
{
... //Rest of Code
Note that your Book struct is already a linked list implementation, so you don't need the LinkedList class at all, or alternatively you don't need the 'next' element of the struct.
But there's no reason from the last (long) code snippet you pasted to have an error at the lines you indicated. node->title = newTitle should copy the string in newTitle to the title field of the struct. The string object is fixed size so it's not possible to overwrite any buffer and cause a seg fault.
However, there may be memory corruption from something you do further up the code, which doesn't cause an error until later on. The thing to look for is any arrays, including char[], that you might be overfilling. Another idea is you mention you save method parameters. If you copy, it's ok, but if you do something like
char* f() {
char str[20];
strcpy(str, "hello");
return str;
}
...then you've got a problem. (Because str is allocated on the stack and you return only the pointer to a location that won't be valid after the function returns.) Method parameters are local variables.
The answer you seek can be found here.
In short: the memory malloc returns does not contain a properly constructed object, so you can't use it as such. Try using new / delete instead.

Returning string from a remote server using rpcgen

I am going through RPC tutorial and learn few techniques in rpcgen. I have the idea of adding, multiplying different data types using rpcgen.
But I have not found any clue that how could I declare a function in .x file which will return a string. Actually I am trying to build a procedure which will return a random string(rand string array is in server).
Can any one advise me how to proceed in this issue? It will be helpful if you advise me any tutorial regarding this returning string/pointer issue.
Thank you in advance.
Ok, answering to the original question (more than 2 years old), the first answer is correct but a little tricky.
In your .x file, you define your structure with the string inside, having defined previously the size of the string:
typedef string str_t<255>;
struct my_result {
str_t data;
};
...
Then you invoke rpcgen on your .x file to generate client and server stubs and .xdr file:
$rpcgen -N *file.x*
Now you can compile client and server in addition to any program where you pretend to use the remote functions. To do so, I followed the "repcgen Tutorial" in ORACLE's web page:
https://docs.oracle.com/cd/E19683-01/816-1435/rpcgenpguide-21470/index.html
The tricky part is, although you defined a string of size m (array of m characters) what rpcgen and .xdr file create is a pointer to allocated memmory. Something like this:
.h file
typedef char *str_t;
struct my_result {
int res;
str_t data;
};
typedef struct my_result my_result;
.xdr file
bool_t xdr_str_t (XDR *xdrs, str_t *objp)
{
register int32_t *buf;
if (!xdr_string (xdrs, objp, 255))
return FALSE;
return TRUE;
}
So just take into account when using this structure in your server side that it is not a string of size m, but a char pointer for which you'll have to reserve memory before using it or you'll be prompted the same error than me on execution:
Segmentation fault!
To use it on the server you can write:
static my_result response;
static char text[255];
memset(&response, '\0', sizeof(my_result));
memset(text, '\0', sizeof(text));
response.data = text;
And from there you are ready to use it wisely! :)
According to the XDR protocol specification you can define a string type where m is the length of the string in bytes:
The standard defines a string of n (numbered 0 to n -1) bytes to be the number n encoded as an unsigned integer (as described above), and followed by the n bytes of the string. Each byte must be regarded by the implementation as being 8-bit transparent data. This allows use of arbitrary character set encodings. Byte m of the string always precedes byte m +1 of the string, and byte 0 of the string always follows the string's length. If n is not a multiple of four, then the n bytes are followed by enough (0 to 3) residual zero bytes, r, to make the total byte count a multiple of four.
string object<m>;
You can then define a struct with the string type str_t as one of the variables:
typedef string str_t<255>;
struct my_result {
str_t data;
};
Then in your .x file you can define an RPC in your program which returns a struct of type my_result. Since rpcgen will give you a pointer to this struct (which I have called res) you can print the message with prinf("%s\n", res->data);.
program HELLO_PROG {
version HELLO_VERSION {
my_result abc() = 1;
} = 1;
} = 1000;

Arena Allocator Allocation Method & Violation Writing Issue

Basically I'm trying to create an Arena Allocator without using structs, classes, or the new operator to manually manage memory. I have a defined size, a character pool, an allocation method and a freeMemory display method.
Note that pool[0] is my index which will keep track of where the memory has last been filled.
const int size = 50000;
char pool[size];
void start() {
pool[0] = 1;
}
int freeMemory(void) {
int freemem = 0;
for(int i = 0; i < size; i++) {
if(pool[i] == NULL) {
freemem++;
}
}
return freemem;
}
void* allocate(int aSize)
{
if(freeMemory() == 0)
{
out();
}
else
{
char* p = NULL;
int pos = pool[0];
pool[pos] = (char) a;
p = &pool[pos];
pool[0] += a;
return((void*) &pool[pos]);
}
}
In the main.cpp:
start();
long* test1 = (long *) allocate(sizeof(long));
cout << freeMemory() << endl; //Returns 49999
*test1 = 0x8BADF00D; //Breaks here
cout << freeMemory() << endl;
It breaks when I try to use 0x8BADF00D and I believe I'm having issues initializing some of these variables too.
Unhandled exception at 0x000515f7 in MemoryManagerC.exe: 0xC0000005: Access violation writing location 0x00000004 on 0x8BADF00D
The code below has numerous bugs.
char* pointer;
for(int i = 0; i < size; i++)
{
*pointer = pool[i];
if(pointer != NULL)
{
pointer = (char*) a;
return((void*) i); //return the pointer
}
}
This line copies a character to an unknown memory location. Since pointer has never been initialized, we can only guess where it's pointing
*pointer = pool[i];
You probably meant to copy a pointer.
pointer = &pool[i];
Although if you did mean to copy a pointer from the pool array, this will always be true. None of the elements in that array reside at address NULL.
if(pointer != NULL)
Now this code changes pointer to point to...more invalid addresses. When a is sizeof(long), that size is reinterpreted to be a memory address. Memory address 0x00000004 most likely.
pointer = (char*) a;
And then this will return the address 0x00000000, in your case. Because i is 0.
return((void*) i); //return the pointer
There are some problems with allocate:
char* pointer = NULL;
int pos = pool[0];
pool[0] is a char. It's not big enough to store indexes to all members of the array.
pool[pos] = (char) a;
I'm not sure what you're storing here, or why. You seem to be storing the size of the allocation in the space that you're allocating.
pointer = &pool[pos + a];
I think you're constructing a pointer to the memory after the allocated portion. Is that right?
pool[0] += a;
And here you're incrementing the offset that shows how much of the pool is allocated, except that a single char isn't going to be big enough for more than a tiny quantity of allocations.
return((void*) &pointer);
And now you're returning the address of the pointer variable. That's going to be an address on the stack, and unsafe to use. Even if you just the contents of pointer instead of its address, I think it would point after the region you just allocated in your pool.
There are also problems with freeMemory. It compares the contents of the pool (char elements) with NULL. This suggests you think it contains pointers, but they are just chars. It's not clear why unallocated parts of the pool would be 0. Do you even allow deallocation within the pool?
Perhaps you could explain how you intend the allocator to work? There's obviously a gap between what you think it should do and what it actually does, but it's not clear what you think it should do, so it's hard to give advice. How do you apportion space in the array? Do you allow deallocation? What information is supposed to be encoded where?
I just realised that allocate uses the undefined variable a. Is that supposed to be the same thing as the parameter aSize? That's what I assume here.
a possible problem with your code might be here.
char* pointer;
for(int i = 0; i < size; i++)
{
*pointer = pool[i];
The thing here is this might work on some compilers (it shouldn't in my opinion).
pointer here is not pointing to anything allocated. So when you do
*pointer = pool[i];
Where should pool[i] be copied to?
For example let's say we delclared pointer like this.
char* pointer = NULL;
now it is clear that
*pointer = pool[i];
is wrong.
g++ (I have noticed) initializes pointers to NULL. So your code will segfault. VC++ might work because it didn't NULL initialize pointer. But you are writing to a memory location that's not yours.

Resources