2012-05-08 8 views
5

Es ist lange her, seit ich C++ benutzt habe, und noch länger, seit ich mich mit harten Typen beschäftigt habe. Ich bin einfach auf der Suche nach einem arbeiten ein Liner, um ein Argument von v8 zu bekommen, oder einen Standardwert, wenn ein Argument nicht geliefert wurde.Kürzeste Möglichkeit (Einzeiler), um ein Standardargument aus einer v8-Funktion zu erhalten?

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

Ausgänge:

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

Leider ist die folgende close-to-ideale Lösung ist für mich nicht (irgendwelche Ideen warum?):

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

Ich gebe zu, ich weiß nicht, zu viel über v8, aber Ihr Ersatz sieht mächtig verdächtig aus einer C++ POV mir: Wann arg0/arg1/arg2 der Destruktoren laufen? Wann laufen diese Destruktoren in Ihrem One-Liner? Was passiert mit dem zugewiesenen Speicher, wenn der Destruktor der Klasse ausgeführt wird? – hvd

+0

Hah, oh Gott ...also afaik (abgesehen von der Tatsache, dass alles in v8 statisch und für die Speicherverwaltung schrecklich ist, weil es eine JS-Engine ist, die überall Zugriff auf alles benötigt): args * könnte * zerstört werden, sobald meine Funktion zurückkehrt ... aber .. es ist sehr möglich dass v8 hängt an den Daten für seine interne "Stack-Tracing". Grundsätzlich weiß ich es nicht positiv, ich werde definitiv den Code erstellen, wenn es fertig ist. ;) –

+0

Convoluted One Liner sind nicht gerade die "saubersten" Lösungen. –

Antwort

8

Vyacheslav Egorov es genagelt Mit seinem Kommentar war es zu der Zeit, als ich auf die Schnur zuging, zerstört worden. Schließlich landete ich mit:

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

Verwendungsbeispiel:

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

    ... 
} 
+2

P.S. Ich akzeptiere eine bessere Antwort als meine eigene. Ich hasse es wirklich, meine eigenen Fragen zu beantworten. –

3

Dieses Stück Code funktioniert gut für mich, einen String-Wert aus einem v8 Wert in einer Zeile zum Extrahieren:

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

Der Konstruktor std :: string sollte Ihre Standardszenarien ohne zusätzlichen Code verarbeiten. Wenn Sie jedoch manuell nach Nullwerten suchen müssen, ist dies trivial.

Dieser Code dient als Beispiel, er erhält String-Werte aller Argumente und druckt sie auf stdout, und fügt sie natürlich in ein nettes Array ein, denn was nutzt es, sie auszudrucken?

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 ist richtig, dass in der temporären AsciiValue Objekt automatisch zerstört wie ein Smart-Pointer in der kompakten Notation wurde:

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

Dies liegt daran, die AsciiValue hat in diesem einzigen außerhalb des Gültigkeitsbereichs gegangen -Zeilumfang

Stattdessen sollte es zerfallen in zwei Zeilen, wenn Sie beabsichtigen, die ‚zwischengespeichert‘ mehrmals Zeiger zu verwenden:

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

Wenn nur die Absicht, einmal den String-Wert zu verwenden, ist es immer noch völlig in Ordnung ist, zu verwenden die kompakte Notation:

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

die doSomethingWithString Funktion ruft den richtigen Wert zu arbeiten. Nur bei der Rückkehr von ihm, dann die Utf8Value wenn automatisch zerstört.

Das Gleiche passiert für String :: AsciiValue.

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