Shortest way (one-liner) to get a default argument out of a v8 function?

It's been a long time since I've used C++, and even longer since I wrapped my head around hard types. I'm simply looking for a working one liner to do get an argument from v8, or a default value when an argument wasn't supplied.

v8::String::Utf8Value arg0(args[0]);
v8::String::Utf8Value arg1(args[1]);
v8::String::Utf8Value arg2(args[2]);
const char *username = (args.Length() > 0) ? *arg0 : "";
const char *password = (args.Length() > 1) ? *arg1 : "";
const char *service = (args.Length() > 2) ? *arg2 : "login";

Outputs:

func(); // { username: "", password: "", service: "login" }
func('1'); // { username: "1", password: "", service: "login" }
func('1', '2'); // { username: "1", password: "2", service: "login" }
func('a', 'b', 'c'); // { username: "a", password: "b", service: "c" }

Unfortunately, the following close-to-ideal solution doesn't work for me (any ideas why?):

const char *username = (args.Length() > 0) ? *v8::String::Utf8Value(args[0]->ToString()) : "";
const char *password = (args.Length() > 1) ? *v8::String::Utf8Value(args[1]->ToString()) : "";
const char *service = (args.Length() > 2) ? *v8::String::Utf8Value(args[2]->ToString()) : "login";

Vyacheslav Egorov nailed it with his comment, by the time I was accessing the string, it had been destroyed. Ultimately I ended up using:

char *get(v8::Local<v8::Value> value, const char *fallback = "") {
    if (value->IsString()) {
        v8::String::AsciiValue string(value);
        char *str = (char *) malloc(string.length() + 1);
        strcpy(str, *string);
        return str;
    }
    char *str = (char *) malloc(strlen(fallback) + 1);
    strcpy(str, fallback);
    return str;
}

Usage Example:

v8::Handle<v8::Value> myMethod(const v8::Arguments &args) {
    char *username = get(args[0], "user");
    char *password = get(args[1], "pass");

    ...
}

This bit of code worked well for me for extracting a string value from a v8 value in one line:

std::string tempString(*v8::String::Utf8Value(args[someInteger]));

The std::string constructor should handle your default scenarios without need for additional code, but if you do need to manually check for null values, this is trivial.

This code serves as an example, it gets string values of all the arguments and prints them to stdout, and of course puts them into a nice array, because what use is printing them out?

std::string* printAllArgs(const Arguments& args){
    std::cout << "PRINTING ALL ARGS: ";
    std::string* stringArray = new std::string[args.Length()];
    for(int i = 0; i < args.Length(); i++){
        std::string tempString(*v8::String::Utf8Value(args[i]));
        stringArray[i] = tempString;
        std::cout << tempString << ";";
    }
    return stringArray;
}

Egorov is correct in that the temporary AsciiValue object has been auto-destroyed like a smart pointer in the compact notation:

const char *username = *v8::String::Utf8Value(args[0]->ToString());
//transient AsciiValue object has gone out of scope, and its destructor has been called in
//  previous line, rendering the pointer (content) invalid henceforth!
...

This is because the AsciiValue has gone out of scope in that single-line scope.

Instead, should break it up into 2 lines if you intend to use the 'cached' pointer several times:

{
  v8::String::Utf8Value usernameObj(args[0]->ToString());
  const char *username = *usernameObj;
  ...
  //use username pointer as often as desired; it remains valid in this entire scope.
  doSomethingWithString(username); //OK

  //can also dereference Utf8Value object only when needed:
  doSomethingWithString(*usernameObj); //OK
}
//here, usernameObj is out of scope and is destroyed, and username will become invalid.

If only intending to use the string value once, it is still perfectly OK to use the compact notation:

doSomethingWithString(*v8::String::Utf8Value(args[0]->ToString())); //OK

The doSomethingWithString function gets the correct value to work with. Only upon returning from it, then the Utf8Value if auto-destroyed.

Same thing happens for String::AsciiValue.