2012-05-08 9 views
5

E 'passato molto tempo da quando ho usato C++, e ancora di più da quando ho messo la testa sui tipi più duri. Sto semplicemente cercando uno funzionante a un liner per ottenere un argomento dalla v8, o un valore predefinito quando non è stato fornito un argomento.Il modo più breve (one-liner) per ottenere un argomento predefinito da una funzione v8?

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"; 

Uscite:

 
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" } 

Purtroppo, i seguenti close-to-ideale soluzione non funziona per me (tutte le idee perché?):

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"; 
+0

Ammetto che non so molto di v8, ma la tua sostituzione sembra molto sospettosa da un POV di C++: quando si eseguono i distruttori di arg0/arg1/arg2? Quando quei distruttori corrono nella tua unica nave? Cosa succede alla memoria allocata quando viene eseguito il distruttore della classe? – hvd

+0

Hah, oh Dio ...così afaik (a parte il fatto che tutto nella v8 è statico e orribile per la gestione della memoria perché è un motore JS che ha bisogno di accedere a tutto ovunque): args * potrebbe * essere distrutto una volta che la mia funzione ritorna ... ma .. è molto possibile che v8 si blocca sui dati per il suo "tracciamento dello stack" interno. Fondamentalmente, non lo so in modo positivo, definirò sicuramente il codice una volta finito. ;) –

+0

I singoli riquadrati non sono esattamente le soluzioni "più pulite". –

risposta

8

Vyacheslav Egorov inchiodato con il suo commento, quando stavo accedendo alla stringa, era stato distrutto. In definitiva ho finito per usare:

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; 
} 

Utilizzo Esempio:

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

    ... 
} 
+2

P.S. Accetterò una risposta migliore della mia. Odio davvero rispondere alle mie stesse domande. –

3

Questo bit di codice ha funzionato bene per me per l'estrazione di un valore di stringa da un valore v8 in una sola riga:

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

Il costruttore std :: string dovrebbe gestire gli scenari predefiniti senza necessità di codice aggiuntivo, ma se è necessario verificare manualmente i valori nulli, questo è banale.

Questo codice serve come esempio, ottiene i valori di stringa di tutti gli argomenti e li stampa su stdout e, naturalmente, li inserisce in un array piacevole, perché a cosa serve stamparli?

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; 
} 
2

Egorov è corretta in quanto l'AsciiValue oggetto temporaneo è stato auto-distrutta come un puntatore intelligente nella notazione compatta:

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! 
... 

Questo perché il AsciiValue va portata in quel singolo ambito di applicazione.

Invece, dovrebbe suddividerlo in 2 righe se si intende utilizzare il puntatore 'cache' diverse volte:

{ 
    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. 

Se solo l'intenzione di utilizzare il valore della stringa una volta, è ancora perfettamente OK per utilizzare la notazione compatta:

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

la funzione doSomethingWithString ottiene il valore corretto da lavorare. Solo al ritorno da esso, quindi il Utf8Value se distrutto automaticamente.

La stessa cosa accade per String :: AsciiValue.

0
string bi = info[0]->IsUndefined() ? "backwardIndex.dat" : string(*Nan::Utf8String(info[0])); 
Problemi correlati