2016-08-08 9 views
0

In einer Bemühung Verbindung Zuordnung in C++ zu lernen, habe ich den folgenden Code zu zeigen, was sie tun:Optimizing Wiederholung Zuordnung von Variablenwerten

int b05; 
int b06 = 13; 

b05 = 49; 
b05 += b06; // b05 = b05 + b06 
cout << "(+=) compound assignment: " << b05 << endl; 

b05 = 49; 
b05 -= b06; // b05 = b05 - b06 
cout << "(-=) compound assignment: " << b05 << endl; 

b05 = 49; 
b05 *= b06; // b05 = b05 * b06 
cout << "(*=) compound assignment: " << b05 << endl; 

b05 = 49; 
b05 /= b06; // b05 = b05/b06 
cout << "(/=) compound assignment: " << b05 << endl; 

b05 = 49; 
b05 %= b06; // b05 = b05 % b06 
cout << "(%=) compound assignment: " << b05 << endl; 

b05 = 49; 
b05 >>= b06; // b05 = b05 >> b06 
cout << "(>>=) compound assignment: " << b05 << endl; 

b05 = 49; 
b05 <<= b06; // b05 = b05 << b06 
cout << "(<<=) compound assignment: " << b05 << endl; 

b05 = 49; 
b05 &= b06; // b05 = b05 & b06 
cout << "(&=) compound assignment: " << b05 << endl; 

b05 = 49; 
b05 ^= b06; // b05 = b05^b06 
cout << "(^=) compound assignment: " << b05 << endl; 

b05 = 49; 
b05 |= b06; // b05 = b05 | b06 
cout << "(|=) compound assignment: " << b05 << endl; 

Wie Sie sehen können, habe ich den Wert von 49 neu zuweisen zu b05, weil die vorherige Operation die Werte ändert.

Gibt es eine Möglichkeit, dies zu umgehen? Oder gibt es eine effizientere Methode, um dieselbe Ausgabe zu erzielen? (Ich würde ein Codebeispiel schätzen)

+0

Sie müssen * b06 nicht erneut zuweisen, es wird nicht durch die zusammengesetzte Operation geändert. – kfsone

+0

Dieser Code sieht komisch aus, komisch, komisch. –

Antwort

2

Sie könnten mit einem Makro so etwas tun:

#define compound(op) \ 
    b05 = 49; \ 
    b05 op b06; \ 
    std::cout << "(" << #op << ") compound assignment: " << b05 << std::endl; 

Dann sind Sie es so nennen:

int b05, b06 = 13; 

compound(+=) 
compound(/=) 
// etc... 

Was dies bedeutet, effektiv, ist das Ersetzen von Text bei der Kompilierung. An jeder Stelle, an der Sie eine compound(...) haben, wird diese durch den Text des zusammengesetzten Makros ersetzt, wobei op durch das ersetzt wird, was Sie in den Klammern angegeben haben (in diesem Fall eine Art Operator).

Um dies in Aktion zu sehen, machen Sie g++ -E <codefile> und Sie werden sehen, dass das Makro (und alle Includes) erweitert wurde.

+2

Don 't empfehlen Makro-Lösungen bitte. Diese sind meistens ungeeignet für das Schreiben von C++ Code. –

+0

Inline-Funktionen bevorzugen Makros. Funktionen haben Typ Sicherheit, Makros nicht. –

+0

Gute Antwort. Zweifellos wird jemand kommen und 10 Seiten Code posten, um dasselbe ohne Makros zu erreichen, und behaupten, dass es "besser" ist, weil es kein Makro verwendet –

1

Sie haben zusammengesetzte Operationen missverstanden. Sie betreffen nur den linken Wert des Ausdrucks.

#include <iostream> 

int main() { 
    int b05 = 10; int b06 = 5; 
    b05 |= b06; 
    std::cout << "b05 " << b05 << ", b06 " << b06 << "\n"; 
} 

http://ideone.com/5nT7pR

Ausgänge:

b05 15, b06 5 

b06 war unverändert.

+0

Ja, das habe ich erst nach dem Posten bemerkt. Ich werde den Code für zukünftige Zuschauer aktualisieren. –

2

Zunächst einmal gibt es keinen besonderen Grund für Ihre Variablen b05 und b06 genannt werden, also lassen Sie uns verwenden a und b, es weniger hässlich aussieht.

Grundsätzlich möchten Sie eine Kopie Ihres Wertepaares (zwei Eingänge, 49 und 13) erstellen und eine Kopie an den Code übergeben, der sie ändert.

Die einfachste Lösung ist, dass Sie zwei zusätzliche Variablen erstellen, weisen Sie Ihre Werte zu ihnen:

int a0 = 49, b0 = 13; 

und sie dann jedes Mal, die Sie verwenden möchten, können Sie die Zuordnung kopieren:

a = a0; b = b0; 

Dies vermeidet doppelte Konstanten (Sie geben nur 49 und 13 einmal), aber Sie müssen immer noch Operatoren kopieren, die Variablen kopieren. Mit struct

(1):

Alle weiteren Verbesserungen werden Sie diese Kopie nicht zulassen, vermeiden, hat es noch vor jeder Operation durchgeführt werden, aber Sie können einige Quellcode Duplizierung mit ein paar Tricks vermeiden.Das lässt Sie zwei Werte in einem kapseln:

struct params { 
    int a; 
    int b; 
} 

params p0; 
p0.a = 49; 
p0.b = 13; 

params p; 

... 
p = p0; 
p.a += p.b; // p.a = p.a + p.b 
cout << "(+=) compound assignment: " << p.b << endl; 
... 

Jetzt sind Sie nur einen Befehl p = p0 statt zwei zu wiederholen.

(2) Mit Wertparameter:

void test1(int a, int b) { 
    a += b; cout << "(+=) compound assignment: " << a << endl; 
} 
void test2(int a, int b) { 
    a -= b; cout << "(-=) compound assignment: " << a << endl; 
} 
... 

int main() { 
    int a = 49; int b = 13; 
    test1(a, b); 
    test2(a, b); 
    ... 
    return 0; 
} 

Obwohl nicht explizit die Zuweisung erfolgt a und b, die Kopie immer noch jedes Mal: ​​aktuelle Parameter a und b von main werden in formalen Parametervariablen von Funktionen kopiert, zufällig auch a und b genannt.

(3) Sie können vermeiden, Code mit Funktionsreferenzen zu duplizieren. Hier ist ein Beispiel mit Array von anonymen Funktionen für jede Operation:

typedef int OperationFn(int, int) 

struct OperationInfo { 
    std::string label; 
    OperationFn op; 
} 

OperationInfo operations[9] = { 
    { "+=", [](int a, int b) { return a += b } }, 
    { "-=", [](int a, int b) { return a -= b } }, 
    { "*=", [](int a, int b) { return a *= b } }, 
    { "/=", [](int a, int b) { return a /= b } }, 
    { "%=", [](int a, int b) { return a %= b } }, 
    { ">>=", [](int a, int b) { return a >>= b } }, 
    { "<<=", [](int a, int b) { return a <<= b } }, 
    { "&=", [](int a, int b) { return a &= b } }, 
    { "^=", [](int a, int b) { return a ^= b } }, 
} 

int main() { 
    for (int i = 0; i < 9; i++) { 
    const OperationInfo& oi = operations[i]; 
    cout << "(" << oi.label << ") compound assignment: "; 
    cout << oi.op(49, 13) << endl; 
    } 
    return 0; 
} 

Der Code erwähnt Parameterersetzung nur einmal (oi.op(49, 13) Linie), aber es ist in einer Schleife, so dass er effektiv alle 9 mal ausgeführt wird. Während Code sauberer und kompakter aussieht, gibt es keinen Effizienzgewinn: Sie kopieren immer noch beide Werte vor jedem Test. obwohl

Eine Optimierung ist möglich: Sie einen gemeinsamen const Wert für das zweite Argument verwenden, weil es nie geändert hat:

const int b = 13; 

und dann nicht b um es passieren, nur b verwenden.

Hinweis: Verzeihen Sie meine Tippfehler. Ich habe keinen Compiler zur Hand, also kann ich diesen Code nicht überprüfen. Es kann kleinere Fehler geben. Hinterlassen Sie Kommentare, wenn Sie sie finden, ich werde meinen Beitrag aktualisieren.

0

Vielleicht könnten Sie eine Funktion wie diese machen:

class Obj 
{ 
public: 
    Obj& operator+= (const Obj &) { return *this; } 
    Obj& operator-= (const Obj &) { return *this; } 
}; 

void testFunction(std::function<Obj&(Obj *, const Obj &)> functionToTest) 
{ 
    Object object; 
    Object otherObject; 
    functionToTest(&object, otherObject); 
    cout << "(+=) function test: " << object << endl; 
} 

int main(void) 
{ 
    std::function<Obj&(Obj *, const Obj &)> functionToTest(&Obj::operator+=); 
    testFunction(functionToTest); 

    std::function<Obj&(Obj *, const Obj &)> functionToTest2(&Obj::operator-=); 
    testFunction(functionToTest2); 
} 

Dieser Code ist nicht 100% richtig, aber es sollte Ihnen die Idee geben & das Prinzip gesund ist. Natürlich funktioniert es nicht mit primitiven Typen.

Verwandte Themen