How to free up memory after converting a managed string to UTF-8 encoded unmanaged char*? - visual-c++

I'm not familiar with C++/CLI so not sure how to free up the memory when using the code below (got the solution here and modified a little):
char* ManagedStringToUnmanagedUTF8Char( String^ s )
{
array<unsigned char> ^bytes = Encoding::UTF8->GetBytes( s );
pin_ptr<unsigned char> pinnedPtr = &bytes[0];
return (char*)pinnedPtr;
}
The above code is working when I tested it by writing the char in a text file. Please let me know if I'm missing something (need to clean up pinnedPtr?).
Now when I use it:
char* foobar = ManagedStringToUnmanagedUTF8Char("testing");
//do something with foobar
//do I need to free up memory by deleting foobar here?
//I tried 'delete foobar' or free(foobar) but it crashes my program

Hans Passant's comment is correct that the returned pointer to the buffer can be moved in memory by the garbage collector. This is because, when the function stack unwinds, pin_ptr will unpin the pointer.
The solution is to
Obtain the System::String buffer and pin it so that the GC cannot
move it.
Allocate memory on the unmanaged heap (or just heap) where
it is not under the GC's jurisdiction, and cannot be moved by the
GC.
Copy memory (and convert to desired encoding) from the
System::String buffer to the buffer allocated on the unmanaged heap.
Unpin the pointer so the GC can once again move the System::String
in memory. (This is done when pin_ptr goes out of the function
scope.)
Sample code:
char* ManagedStringToUnmanagedUTF8Char(String^ str)
{
// obtain the buffer from System::String and pin it
pin_ptr<const wchar_t> wch = PtrToStringChars(str);
// get number of bytes required
int nBytes = ::WideCharToMultiByte(CP_UTF8, NULL, wch, -1, NULL, 0, NULL, NULL);
assert(nBytes >= 0);
// allocate memory in C++ where GC cannot move
char* lpszBuffer = new char[nBytes];
// initialize buffer to null
ZeroMemory(lpszBuffer, (nBytes) * sizeof(char));
// Convert wchar_t* to char*, specify UTF-8 encoding
nBytes = ::WideCharToMultiByte(CP_UTF8, NULL, wch, -1, lpszBuffer, nBytes, NULL, NULL);
assert(nBytes >= 0);
// return the buffer
return lpszBuffer;
}
Now, when using:
char* foobar = ManagedStringToUnmanagedUTF8Char("testing");
//do something with foobar
//when foobar is no longer needed, you need to delete it
//because ManagedStringToUnmanagedUTF8Char has allocated it on the unmanaged heap.
delete foobar;

I'm not familiar with Visual-C++ either, but according to this article
Pinning pointers cannot be used as: [...] the return type of a function
I'm not sure whether the pointer will be valid when the function ends (even though it's disguised as a char*.
It seems that you declare some local variables in the function that you want to pass to the calling scope. 'However, possibly these will be out of scope anyway when you return from the function.
Maybe you should reconsider what you are trying to achieve in the first place?
Note, that in the article you have referenced a std::string (passed by value, i.e. by copy) is used as return parameter.
std::string managedStringToStlString( System::String ^s )
{
Encoding ^u8 = Encoding::UTF8;
array<unsigned char> ^bytes = u8->GetBytes( s );
pin_ptr<unsigned char> pinnedPtr = &bytes[0];
return string( (char*)pinnedPtr );
}
Thereby no local variables are passed out of their scope. The string is handled over by copy as an unmanaged std::string. This is exactly what this post suggests.
When you need a const char* later, you can use the string::c_str() method to get one. Note, that you can also write std::string to a file using file streams.
Is this an option for you?

Related

Confused use of memcpy in ext2fs library

I am reading the source code implementation of libext2fs, which is part of the project e2fsprogs used to debug Ext2/3/4 file systems. And came across one confused point about the use of method memcpy as follows.
In the library, it maintains one function ext2fs_get_mem which is used to allocate dynamic memories:
_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
{
void *pp;
pp = malloc(size);
if (!pp)
return EXT2_ET_NO_MEMORY;
memcpy(ptr, &pp, sizeof (pp));
return 0;
}
The caller will call it like:
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs)
In the above case, variable fs is just type of struct struct_ext2_filsys, all right.
The confused point is why the function ext2fs_get_mem need to call memcpy and what's the purpose? Why not directly allocate memory to the pointer void *ptr by malloc?

Writing buffer to BYTE* using CURL

How to write a request buffer to a variable of type BYTE*? I have alreay tried the write own func CURLOPT_WRITEFUNCTION - https://pastebin.com/UBrp7Wyx and set the CURLOPT_WRITEDATA to
BYTE* raw_data = nullptr;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &raw_data);
Actually, why you need to store BYTE type? If you want to use CURL for websites and want to accept some extended symbols (like cyrillic), you will not get expected behaviour (for example, UTF-8 has backward compatibility with ASCII, so simple reinterpret or +128 to each symbol will not help). It will have same behaviour as if you converting some char buffer to something else.
So code like this with simple chars work fine:
...
// yours write_function
size_t curlWriteFunc(char* data, size_t size, size_t nmemb, std::string* buffer)
{
size_t result = 0;
if (buffer != NULL)
{
buffer->append(data, size * nmemb);
result = size * nmemb;
}
return result;
}
int main()
{
... // some prepares, setting up easy_handler and so on
std::string buffer;
// set up write function and pointer to buffer
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curlWriteFunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
... // make request and other things
}
However, if you are using CURL not for websites but for own client, which recives some binary data and BYTE is required, you will have to use some own struct which contains BYTE *, controls allocated size and reallocate memory if needed... Or just use vector<BYTE>.
You need a data structure to accumulate data as it comes in, a std::string suffices for that.
At the end, you can then simply do: (assuming you have a std::string s)
BYTE * raw_data = (BYTE *)s.data();
Note that the raw_data pointer is only valid for as long as the string is alive. If you need to contents to survive for longer than that, use a heap allocation and memcpy:
BYTE * raw_data = new BYTE[s.size()];
memcpy(raw_data, s.data(), s.size());
Note that you need to delete[] raw_data yourself at some point.

Qt4: how to send QString inside a struct via QSharedMemory

I have a struct
struct control_data{
int column_number;
QString cell;
};
I need to send it to another thread with the help of QShareMemory. I read that you can't do this because QString contains pointers inside. Any other ways?
You have to serialize your struct to a Byte array. You can always convert your QString to a const char* like this:
myString.toStdString().c_str();
But serializing a QString should work.
The first step is to serialize your struct to a QDatastream using Qt, example here.
Then once your struct can be read and written you can pass it to a shared memory.
A complete example of using QSharedMemory can be found here.
Here is the relevant code:
// First, test whether a shared memory segment is already attached to the process.
// If so, detach it
if (sharedMem.isAttached())
{
sharedMem.detach();
}
...
QBuffer buffer;
buffer.open( QBuffer::ReadWrite );
QDataStream out( &buffer );
out << youStruct;
int size = buffer.size(); // size of int + size of QString in bytes
if ( !sharedMem.create( size ) ) {
return;
}
// Write into the shared memory
sharedMem.lock();
char *to = (char*)sharedMem.data();
const char *from = buffer.data().data();
memcpy( to, from, qMin( sharedMem.size(), size ) );
sharedMem.unlock();

Dynamic Memory Deletion in vc++

I am using _aligned_malloc in my code. But it is throwing error error as shown in image.
CString sBuffer = _T("Hello");
TCHAR* pBuffer;
pBuffer = (TCHAR *)_aligned_malloc(1024, 16);
if (pBuffer == NULL) {
...............Error .. msg
}
pBuffer = sBuffer.GetBuffer(sBuffer.GetLength());
..................................................
.........................................................
sBuffer.ReleaseBuffer(sBuffer.GetLength());
if (pBuffer != NULL) {
_aligned_free(pBuffer);
}
The CString class implements (LPCTSTR) cast operator that you can use to get const TCHAR*.
Please note that TCHAR is defined as char in MBCS mode, and as wchar in UNICODE mode. For more details please refer to tchar.h where its defined.
If you'd like to modify the content of the buffer you'll need to use GetBuffer() method. Don't forget to call ReleaseBuffer() when you done. So, there is no need to allocate memory manually.
You can also easily construct CString from TCHAR*. There is a constructor to do that.

std::string.c_str() returning a weird characters

In my project, I use to load textures by specifying its file name. Now, I made this function const char* app_dir(std::string fileToAppend); that returns the mains argv[0] and change the application name by the fileToAppend. Since I cannot make the string manipulation easy with a char*, I use the std::string. My texture loader takes a const char* for file name so need to switch back to c_str(), now it generates a sequence of ASCII symbol characters (bug). I already fix the problem by changing the return type of the app_dir() to std::string. But why is that happening?
EDIT
sample code:
//in main I did this
extern std::string app_filepath;
int main(int argc, char** arv) {
app_filepath = argv[0];
//...
}
//on other file
std::string app_filepath;
void remove_exe_name() {
//process the app_filepath to remove the exe name
}
const char* app_dir(std::string fileToAppend) {
string str_app_fp = app_filepath;
return str_app_fp.append(fileToAppend).c_str();
//this is the function the generates the bug
}
I already have the functioning one by changing its return type to std::string as I said earlier.
A big no no :) returning pointer to local objects
return str_app_fp.append(fileToAppend).c_str();
Change your function to
std::string app_dir(const std::string& fileToAppend) {
string str_app_fp = app_filepath + fileToAppend;
return str_app_fp;
}
And on the return value use c_str()
When you using function const char* app_dir(std::string fileToAppend); you get pointer to the memory that allocated on the stack and already deleted when the function ends.

Resources