Ho appena usato una dichiarazione goto. Va bene? [chiuso]

-1

Ho appena scritto questo codice che utilizza un'istruzione goto.

if (PyMethod_Check(attrib_value)) {
    PyObject *im_self = PyObject_GetAttrString(attrib_value, "im_self");
    if (im_self == Py_None) {
        js_value = FunctionTemplate::New(isolate, py_class_method_callback, js_name, signature);
    } else {
        goto method_counts_as_function;
    }
    Py_DECREF(im_self);
} else if (PyFunction_Check(attrib_value)) {
method_counts_as_function:
    js_value = ((py_function *) py_function_to_template(attrib_value))->js_template->Get(isolate);
    templ->Set(js_name, js_value);
} else {
    js_value = js_from_py(attrib_value, no_ctx);
    templ->Set(js_name, js_value);
}

L'intenzione è di trattare determinati metodi come le funzioni. Normalmente userei un && nell'istruzione if, qualcosa come questo:

if (PyMethod_Check(attrib_value) &&
    PyObject_GetAttrString(attrib_value, "im_self) != Py_None) 

Sfortunatamente, PyObject_GetAttrString restituisce un oggetto con un conteggio di riferimento incrementato. Non riesco a decrementare il conteggio dei riferimenti su un valore che potrebbe o meno essere esistito nella seconda parte del cortocircuito e.

Mi sento piuttosto male perché le dichiarazioni goto sono considerate dannose, ma non riesco a pensare a un buon modo per riscrivere questo senza gotos. Va bene?

Codice nel contesto

    
posta tbodt 14.11.2016 - 04:00
fonte

3 risposte

5

Non riesco a pensare a un buon modo per riscrivere questo senza gotos.

Immagino che questo:

if (PyMethod_Check(attrib_value)) {
    PyObject *im_self = PyObject_GetAttrString(attrib_value, "im_self");
    if (im_self == Py_None) {
        js_value = FunctionTemplate::New(isolate, py_class_method_callback, js_name, signature);
    } else {
        goto method_counts_as_function;
    }
    Py_DECREF(im_self);
} else if (PyFunction_Check(attrib_value)) {
method_counts_as_function:
    js_value = ((py_function *) py_function_to_template(attrib_value))->js_template->Get(isolate);
    templ->Set(js_name, js_value);
} else {
    js_value = js_from_py(attrib_value, no_ctx);
    templ->Set(js_name, js_value);
}

... può essere refactored come segue. Metti il primo bit in una subroutine che restituisce true o false a seconda se vuoi fare la cosa speciale:

SUBROUTINE / FUNZIONE:

if (PyMethod_Check(attrib_value)) {
    PyObject *im_self = PyObject_GetAttrString(attrib_value, "im_self");
    if (im_self == Py_None) {
        js_value = FunctionTemplate::New(isolate, py_class_method_callback, js_name, signature);
    } else {
        RETURN TRUE
    }
    Py_DECREF(im_self);

    RETURN FALSE

} else if (PyFunction_Check(attrib_value)) {

RETURN TRUE

}

... and ...

if (SUBROUTINE/FUNCTION){

    /// method_counts_as_function:
    js_value = ((py_function *) py_function_to_template(attrib_value))->js_template->Get(isolate);
    templ->Set(js_name, js_value);
} else {
    js_value = js_from_py(attrib_value, no_ctx);
    templ->Set(js_name, js_value);
}

Sarebbe più complicato se tu avessi anche a disposizione una variabile locale come im_self (per usarla successivamente), ma in questo caso penso che tu non lo faccia.

OK?

link

    
risposta data 14.11.2016 - 05:08
fonte
2

Metti questa linea in una funzione (suppongo che tu possa trovare un nome migliore):

py_function *get_js_value(attrib_value_t attrib_value,isolate_t isolate)
{
     return ((py_function *) py_function_to_template(attrib_value))
                             ->js_template->Get(isolate);
}

Quindi puoi riscrivere il codice come segue:

if (PyMethod_Check(attrib_value)) {
    PyObject *im_self = PyObject_GetAttrString(attrib_value, "im_self");
    if (im_self == Py_None) {
        js_value = FunctionTemplate::New(isolate, py_class_method_callback, js_name, signature);
    } else {
        js_value =get_js_value(attrib_value,isolate);
    }
    Py_DECREF(im_self);
} else if (PyFunction_Check(attrib_value)) { 
  {
      js_value =get_js_value(attrib_value,isolate);
  } else {
      js_value = js_from_py(attrib_value, no_ctx);
  }
  templ->Set(js_name, js_value);
}

(Nota: rimuove anche la duplicazione della parte templ->Set( .)

Sostituisce goto con una chiamata ripetuta alla stessa funzione e lascia il codice in uno stato con quasi nessuna logica duplicata.

    
risposta data 15.11.2016 - 11:32
fonte
0

Il mio suggerimento è quello di "duplicare il codice" e lasciare che il compilatore esegua "Eliminazione sottoespressione comune" (CSE) per te. I compilatori intelligenti dovrebbero essere in grado di trovare la parte comune del codice e generare rami di conseguenza:

if (PyMethod_Check(attrib_value)) {
  PyObject *im_self = PyObject_GetAttrString(attrib_value, "im_self");
  if (im_self == Py_None) {
    js_value = FunctionTemplate::New(isolate, py_class_method_callback, js_name, signature);
    Py_DECREF(im_self); // <<<< moved here
  } else {
    //goto method_counts_as_function;
    js_value = ((py_function *) py_function_to_template(attrib_value))->js_template->Get(isolate);
    templ->Set(js_name, js_value);
  }
  //Py_DECREF(im_self); // moved up >>>>
} else if (PyFunction_Check(attrib_value)) {
//method_counts_as_function:
  js_value = ((py_function *) py_function_to_template(attrib_value))->js_template->Get(isolate);
  templ->Set(js_name, js_value);
} else {
  js_value = js_from_py(attrib_value, no_ctx);
  templ->Set(js_name, js_value);
}

Se il compilatore non riesce a farlo o non ti piacciono i codici duplicati, puoi comunque definire una macro breve o una funzione in linea per la parte duplicata e chiamarla in entrambi i punti.

    
risposta data 14.11.2016 - 05:29
fonte

Leggi altre domande sui tag