Hey, thanks for this wonderful abstraction!
I ran into an issue where using info[0].ToString().Utf8Value().c_str() returned garbled text:
void print(const Napi::CallbackInfo& info) {
const char* word = info[0].ToString().Utf8Value().c_str();
logFile << word << "\n";
}
However, this totally works:
void print(const Napi::CallbackInfo& info) {
std::string str = info[0].ToString().Utf8Value();
const char* word = str.c_str();
logFile << word << "\n";
}
Perhaps there is a gap in my C++ knowledge here.
Let me know if you need more information!
Hi @Wulf,
it should work in the same way. What logFile do? Could you specify your operating system and Node.js version?
I tried this code
#include <napi.h>
#include <iostream>
void PrintOK(const Napi::CallbackInfo& info) {
std::string str = info[0].ToString().Utf8Value();
const char* word = str.c_str();
std::cout << word << "\n";
}
void PrintKO(const Napi::CallbackInfo& info) {
const char* word = info[0].ToString().Utf8Value().c_str();
std::cout << word << "\n";
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "printOK"),Napi::Function::New(env, PrintOK));
exports.Set(Napi::String::New(env, "printKO"),Napi::Function::New(env, PrintKO));
return exports;
}
NODE_API_MODULE(hello, Init)
and I have the same output.
c_str() returns a pointer to the underlying memory location. It is only valid for the lifetime of the string itself. In the code info[0].ToString().Utf8Value().c_str() the std::string is a temporary value and is release immediately after calling c_str(), so the pointer is immediately invalidated.
You are correct that you should assign the string while you're using the pointer returned by c_str().
Hey @NickNaso, thanks for that test snippet. It's working fine for me too. I don't know why it doesn't work here. I'm on ArchLinux using node v11.1.0 and the logFile is just an output file stream:
std::ofstream logFile("log.txt");
@rolftimmermans, thanks for the explanation. How do you suggest keeping the std::string value valid for the lifetime for an asynchronous operation? Should the characters be copied in the constructor of the AsyncWorker?
If you change SpellWorker to use std::string instead of const char* (for the word parameter and the word member) it should work.
@devsnek Cool.
@NickNaso just found out that this problem also occurs in your example if you use a large string. On my machine, 15 characters or more seems to do the trick.
Thanks everyone :rocket:
Most helpful comment
c_str()returns a pointer to the underlying memory location. It is only valid for the lifetime of the string itself. In the codeinfo[0].ToString().Utf8Value().c_str()thestd::stringis a temporary value and is release immediately after callingc_str(), so the pointer is immediately invalidated.You are correct that you should assign the string while you're using the pointer returned by
c_str().