Seite 2 von 4
Re: Is it just me, or …
Verfasst: 13.07.2010, 00:09
von Krishty
Hmmm, interessantes Feature … kannst du mir genauer erklären, wie das funktioniert?
Was zum Beispiel passiert, wenn ich libpng einbinde um PNGs zu laden? Dann müsste doch ein Drittel der dortigen Symbole (nämlich die, die nur zum Schreiben da sind) als unreferenziert angezeigt werden … dann nochmal die Hälfte von zlib (alles, was nur zum Packen statt zum Entpacken da ist) inklusive endloser Listen von Lookup-Tables für Datenverarbeitung und Fehlernachrichten … und 90 % der Symbole der Laufzeitbibliothek sowieso?
Und, naja, wenn der Compiler (bzw. Linker) warnt, dass ein Symbol nicht genutzt wird, dann wird er ja auch in der Lage sein, es wegzulassen. Das bedeutet im Umkehrschluss, dass bei den Symbolen, die wegen dem Unvermögen des Compilers unnötig in der Executable landen, auch keine Warnung kommen würde.
Achja, noch was am Rande: Es scheint dem Optimizer auch einen Unterschied zu machen, ob meine Exception-Klasse einen Zuweisungsoperator hat oder nicht … Programmierung ist echt unberechenbar.
Re: Is it just me, or …
Verfasst: 13.07.2010, 02:33
von Krishty
Paralleles Thema: Gibt es eine Möglichkeit, den vector constructor iterator wegzuoptimieren?
Ich habe ein fixed-size-Array ([100]) eines User-Typs, dessen K’tor nichts anderes macht, als drei Member-Pointer auf 0 zu setzen. Anstatt nun 3×4×100 Bytes zu nullen, wird der vector constructor iterator aufgerufen und ruft den Konstruktor 100 Mal indirekt auf … erscheint mir irgendwie suboptimal :/
Re: Is it just me, or …
Verfasst: 13.07.2010, 08:44
von TGGC
Krishty hat geschrieben:Paralleles Thema: Gibt es eine Möglichkeit, den vector constructor iterator wegzuoptimieren?
Ich habe ein fixed-size-Array ([100]) eines User-Typs, dessen K’tor nichts anderes macht, als drei Member-Pointer auf 0 zu setzen. Anstatt nun 3×4×100 Bytes zu nullen, wird der vector constructor iterator aufgerufen und ruft den Konstruktor 100 Mal indirekt auf … erscheint mir irgendwie suboptimal :/
Konstruktor schreiben, der nichts macht und dann den den Speicherblock mit memset fuellen. f'`8k
Gruß, TGGC (
der kostenlose DMC Download)
Re: Is it just me, or …
Verfasst: 13.07.2010, 08:55
von Alexander Kornrumpf
Krishty hat geschrieben:
Und, naja, wenn der Compiler (bzw. Linker) warnt, dass ein Symbol nicht genutzt wird, dann wird er ja auch in der Lage sein, es wegzulassen. Das bedeutet im Umkehrschluss, dass bei den Symbolen, die wegen dem Unvermögen des Compilers unnötig in der Executable landen, auch keine Warnung kommen würde.
Ich weiß nicht ob Kimmi die "Symbol defined but never used" Warnung meinte aber ich habe die immer so verstanden, dass der Gedanke dahinter ist dass der Programmierer sich vermutlich etwas dabei gedacht hat das Symbol zu definieren und es somit wahrscheinlich ein Irrtum des Programmieres ist dieses dann nicht zu benutzen. Der Charakter der Warnung war für mich immer "Du hast vergessen das Symbol zu benutzen" und nicht "Du hast eine Definition zuviel".
Re: Is it just me, or …
Verfasst: 13.07.2010, 11:11
von kimmi
Teilweise kann es sogar unmöglich für den Compiler sein, nicht referenzierte Symbole wegzulassen: wenn über einen Header solche Dinge durch irgendwelche Kunstgriffe unbenutzte Symbole hinzukommen, die dann aber für andere Dlls wichtig sind. Und ja, das ist mir schon passiert :). Das setzt natürlich voraus, daß diese Symbole external linked sind. Bei Dlls hat das das selber ja in der Hand, bei Libs nur bedingt.
Mir ist es lieber, wenn der Compiler eine Warnung ausspuckt.
Gruß Kimmi
Re: Is it just me, or …
Verfasst: 13.07.2010, 12:29
von Aramis
Man sollte einfach nicht vergessen dass ein Optimizer nichts ist, auf dass man sich 100% verlassen kann. Wenn absolut keine unreferenzierten Symbole drin sein duerfen, gibt es immer noch den Praeprozessor.
Fuer die allermeisten User spielt zudem Geschwindigkeit eine groessere Rolle als Groesse, daher duerfte die Entwicklung des MS-Linkers auch daraufhin ausgelegt sein.
Re: Is it just me, or …
Verfasst: 13.07.2010, 15:10
von Krishty
TGGC hat geschrieben:]Konstruktor schreiben, der nichts macht und dann den den Speicherblock mit memset fuellen.
Leider keine Option, da es kein PoD-Typ ist. Aber selbst, wenn ich es täte (ich habe es aus Verzweiflung gerade probiert) würde es nicht wegoptimiert – es würde in Schleife ein K’tor aufgerufen, der aus nichts als
mov eax, ecx; ret bestünde.
Ich muss mich übrigens korrigieren, der Compiler benutzt den
eh vector constructor iterator – und das wird auch der Knackpunkt sein: Ich vermute, dass der Compiler das tut, weil das Objekt unwindable ist (kein leerer Destruktor). Wahrscheinlich hat da irgendjemand angenommen, dass Objekte, sobald unwindable, auch ausnamesicher initialisiert werden müssen. Da der K’tor hier aber überhaupt keine Ausnahme auslösen
kann (und der Compiler das auch korrekt erkennt, weil er an anderen Stellen entsprechenden Code weglässt) ist es hier auch überflüssig, ausnahmesicher zu initialisieren. Oder sehe ich das falsch?
Alexander Kornrumpf hat geschrieben:Ich weiß nicht ob Kimmi die "Symbol defined but never used" Warnung meinte aber ich habe die immer so verstanden, dass der Gedanke dahinter ist dass der Programmierer sich vermutlich etwas dabei gedacht hat das Symbol zu definieren und es somit wahrscheinlich ein Irrtum des Programmieres ist dieses dann nicht zu benutzen. Der Charakter der Warnung war für mich immer "Du hast vergessen das Symbol zu benutzen" und nicht "Du hast eine Definition zuviel".
Kann es sein, dass diese Warnung nur für den Quellcode der aktuellen Executable getriggert wird und nicht für alles, was zu ihr dazugelinkt wird?
kimmi hat geschrieben:Teilweise kann es sogar unmöglich für den Compiler sein, nicht referenzierte Symbole wegzulassen: wenn über einen Header solche Dinge durch irgendwelche Kunstgriffe unbenutzte Symbole hinzukommen, die dann aber für andere Dlls wichtig sind. Und ja, das ist mir schon passiert :). Das setzt natürlich voraus, daß diese Symbole external linked sind. Bei Dlls hat das das selber ja in der Hand, bei Libs nur bedingt.
Mir ist es lieber, wenn der Compiler eine Warnung ausspuckt.
Ja, eine Warnung wäre mir auch lieb, aber der Compiler hält einfach nur die Klappe und packt die Symbole (wahllos!) mit rein. Achja, was wären das für Kunstgriffe?
Aramis hat geschrieben:Man sollte einfach nicht vergessen dass ein Optimizer nichts ist, auf dass man sich 100% verlassen kann.
Wenn
ich ihn geschrieben hätte, wäre das wohl anders. Aber vielleicht ändert es sich schon, wenn ich das Team weiterhin täglich mit Bug-Reports bombardiere … :)
Aramis hat geschrieben:Fuer die allermeisten User spielt zudem Geschwindigkeit eine groessere Rolle als Groesse, daher duerfte die Entwicklung des MS-Linkers auch daraufhin ausgelegt sein.
Es macht aber schon einen Unterschied, ob ein Linker einfach nur die Hälfte der Symbole weglässt, bei der er am schnellsten feststellen kann, dass sie unbenutzt sind oder ob er absolut gleichberechtigte Symbole ohne jedes nachvollziehbare Muster behält oder nicht. Das eine ist eine Optimierung, das andere imo ein Bug oder zumindest Nachlässigkeit.
Re: Is it just me, or …
Verfasst: 13.07.2010, 15:30
von kimmi
Zum Beispiel einen Int als volatile markieren, damit eine Variable nicht wegoptimiert wird. Oder man zaubert sich mit dem Präprozessor Symbole weg / Dummysymbole hin, um Linkprobleme in den Griff zu kriegen ( für Dummy-Wrapper beliebt, link mal F77, F90, C und C++ Libs zusammen, da kommt Freude auf ). Und ich hatte erst letztens ein Problem mit einem auf dem Heap generierten Objekt, daß unresolved symbols Fehler erzeugt hatte. Auf dem Stack kreiert waren die weg ( flgl heißt die Lib ). Ich hab den Fehler aus Zeitmangel nicht nachvollzogen.
Und wenn ich beim 2008'er das Warninglevel auf 4 stelle, kriege ich zumindest in meinem Code Warnungen für definierte, aber nicht referenzierte Symbole.
Gruß Kimmi
Re: Is it just me, or …
Verfasst: 13.07.2010, 15:33
von Krishty
kimmi hat geschrieben:Und wenn ich beim 2008'er das Warninglevel auf 4 stelle, kriege ich zumindest in meinem Code Warnungen für definierte, aber nicht referenzierte Symbole.
Wtf, ich kompiliere seit Jahren nur mit Warning Level 4. Ich bekomme Warnungen bei unreferenzierten Parametern, unreferenzierten lokalen Objekten – aber noch nie bei unreferenzierten Funktionen oder globalen Objekten. Jetzt muss ich aber mal einen Blick in die Compiler-Einstellungen werfen …
Re: Is it just me, or …
Verfasst: 13.07.2010, 15:37
von kimmi
Ops, sorry! Die Warnungen über nicht referenzierte Funktionen kriege ich von Lint! Ich hab die durch den Tüddel bekommen!
Gruß Kimmi
Re: Is it just me, or …
Verfasst: 13.07.2010, 15:46
von Krishty
Ah, okay! Microsofts statische Code-Analyse schmeißt vergleichbare Warnungen leider nicht. Dafür habe ich jetzt das Warning-Level WAll entdeckt, boah, da geht jedem Pedanten das Herz auf.
Code: Alles auswählen
struct X {
enum {
A,
B,
NumValues,
}; // warning C4820: 'X' : '3' bytes padding added after data member 'NumValues'
int Members[NumValues];
};
Code: Alles auswählen
__assume(x <= 3); // warning C4557: '__assume' contains effect '='
Es hat wohl einen Grund, warum diese Warnungen per default ausgeblendet werden.
Edit: DA!
Warning | 3081 | warning C4514: '_chgsignl' : unreferenced inline function has been removed | X:\Tools\VS2010\VC\include\math.h | 380
und direkt wieder herp derp:
Code: Alles auswählen
__declspec(noinline) void Foo(); // warning C4514: 'Foo' : unreferenced inline function has been removed
Re: Is it just me, or …
Verfasst: 29.07.2010, 23:20
von Krishty
Code: Alles auswählen
inline int Round(double const & Value) {
return ::_mm_cvtsd_si32(::_mm_load_sd(&Value));
}
…
int x = Round(1.0);
=>
Code: Alles auswählen
movsd xmm0,mmword ptr [__real@3ff0000000000000]
movsd mmword ptr [SomeLocalAddress],xmm0
movsd xmm1,mmword ptr [SomeLocalAddress]
cvtsd2si edx,xmm1
War nicht genau
das ein Grund, Intrinsics zu benutzen? (Übrigens ist das ein x64-Build; unter x86 ist der Code
noch ineffizienter, weil
Round() garnicht erst geinlined wird.)
Re: Is it just me, or …
Verfasst: 30.07.2010, 09:30
von kimmi
Wieso nimmst du da nicht einfach floor, der soll gemäß MS-Doku für alle Architekturen ein Intrinsic sein:
Code: Alles auswählen
inline long floor(double val )
{
return (long)floor( val + 0.5 );
}
Das sieht dann auch etwas lesbarer aus und ist definitiv portabler. Keine Ahnung, was da an Assemblercode rausfällt. Außerdem gibst du einen int für einen Double zurück, wahrscheinlich für den absoluten Anteil des Doubles. Eventuell liegt da das Problem, weil double auf Int gecastet werden muß? Ich weiß nicht, wie das auf 64-Bit-Plattformen aussieht. KA!
Gruß Kimmi
Re: Is it just me, or …
Verfasst: 30.07.2010, 12:31
von Krishty
kimmi hat geschrieben:Wieso nimmst du da nicht einfach floor
Weil es nur für positive Zahlen funktioniert und um den Faktor 10 langsamer ist (
floor ist zwar ein Intrinsic, aber nicht nur ein einziger Assembler-Befehl wie es
cvtsd2si ist).
Re: Is it just me, or …
Verfasst: 30.07.2010, 13:01
von kimmi
Das mit dem Langsamer mag sein, aber floor gibt es für float und double. In Kombination mit dem ?-Operator und ceil klappts auch für negative :). Aber da bleibt natürlich das Performance-Problem.
Gruß Kimmi
Re: Is it just me, or …
Verfasst: 30.07.2010, 13:05
von Krishty
Einen entsprechenden SSE-Befehl gibt es auch für float. Und naja, es ist wirklich so, dass floor() und ceil() je einen impliziten Funktionsaufruf mit etwa 30 Befehlen bewirken … da läuft ein einziger SSE-Befehl außer Konkurrenz … auch, wenn der Compiler seinen Aufruf so selten schlecht optimiert. Ist natürlich auch sauber gekapselt und für nicht-MS-Architekturen liegen Intrinsic-lose, langsame, platzverschwendende Alternativen bereit.
(Übrigens optimiert der Compiler jeden Cast zu int sowieso durch den verwandten cvttsd2si-Befehl, der abschneidet, statt zu runden – jede manuelle Methode wäre also zumindest in diesem Punkt redundant)
Re: Is it just me, or …
Verfasst: 30.07.2010, 13:33
von kimmi
Hm, interessant. Ich habe mir den generierten Assemblercode nicht angesehen, sondern habe mal aus der Doku von MS gehofft, die entsprechenden Infos zu kriegen und dass das floor = globaler und vor allem optimierter Intrinsic. Wieder was von dir gelernt!
Gruß Kimmi
Re: Is it just me, or …
Verfasst: 25.09.2010, 00:01
von Krishty
Visual C++ 2010 auf höchsten Optimierungseinstellungen:
Code: Alles auswählen
movss xmm0,dword ptr [esi+4] ; move scalar single-precision floating-point number from stack to xmm0
movsd xmm1,mmword ptr [__real@40019999a0000000] ; load double representation of 2.2 (?) into xmm1
cvtps2pd xmm0,xmm0 ; convert value in xmm0 from single to double
ucomisd xmm1,xmm0 ; compare scalar double-precision floating-point values in xmm0 and xmm1 and set EFLAGS
mov ecx,eax ; save content of eax
lahf ; copy EFLAGS into ah (eax)
test ah,44h ; test if parity and zero flag are set(?)
Wtf is this shit
I don't even …
Re: Is it just me, or …
Verfasst: 25.09.2010, 02:50
von Krishty
… und direkt noch einer hinterher:
Erinnert ihr euch, dass der Compiler manchmal schnelleren Code generieren kann, wenn man den automatischen Zuweisungsoperator benutzt statt einen eigenen zu schreiben? Naja, mit SSE ist es – wie könnte es auch anders sein! – genau umgekehrt. Wenn ihr eine Datenstruktur habt, die einen ausgerichteten 128-Bit-Vektor enthält, schreibt den Zuweisungsoperator bloß selber. Ich habe Vektor, Tupel und XNA-Math-Vektor ineinander verschachtelt und wenn ich die Zuweisung explizit ausschreibe, resultiert es in gerade mal einem Viertel der Befehle – der automatische Zuweisungsoperator kopiert nämlich Wort für Wort, der manuelle auf einen Schlag per movaps.
Und gebt immer by-Reference zurück, falls es möglich ist. By-value erkennt der Compiler nämlich auch kein Alignment.
Re: Is it just me, or …
Verfasst: 25.09.2010, 16:18
von Krishty
Noch ein schönes Beispiel dafür, was für unbeabsichtigten Code
static erzeugt:
Code: Alles auswählen
class CMatrix {
::XMMATRIX MyData;
…
public:
// Default constructor.
CMatrix()
: MyData(::XMMatrixIdentity())
{ }
};
… in function:
static CMatrix Matrix;
Die letzte Zeile kompiliert – wie gewohnt – zu
Code: Alles auswählen
mov eax,dword ptr [1205568h] ; Lade eine Dummy-bool, die der Compiler angelegt hat, um den Initialisierungsstatus zu prüfen
test al,1 ; Schon initialisiert?
jne 11F843Ch ; Dann überspring den Rest
movaps xmm0, { 1., 0., 0., 0. } ; Lade die Einheitsmatrix in die Register …
movaps xmm1, { 0., 1., 0., 0. }
movaps xmm2, { 0., 0., 1., 0. }
movaps xmm3, { 0., 0., 0., 1. }
movaps xmmword ptr [esp+10h], xmm0 ; … und speichere sie in der Matrix-Instanz
movaps xmmword ptr [esp+20h], xmm1
movaps xmmword ptr [esp+30h], xmm2
movaps xmmword ptr [esp+40h], xmm3
or eax,1 ; Setze das Flag auf true, …
mov dword ptr [1205568h],eax ; … und speichere es.
Nun könnte man meinen, der Code entfiele, sobald man im K’tor keine Initialisierung mehr vornimmt. Aber Pustekuchen – es fällt nur der Body weg, die Hülle bleibt:
Code: Alles auswählen
mov eax,dword ptr [1205432h]
test al,1
jne 11F843Ch
or eax,1
mov dword ptr [1205432h],eax
Da schwirrt nun ein Herrenloses
bool in den globalen Daten herum, dessen Dasein darin besteht, unentwegt abgefragt und beim ersten Mal auf
true gesetzt zu werden. Captain Fantastic. Ich hasse
static.
Re: Is it just me, or …
Verfasst: 23.11.2010, 13:18
von Krishty
Kann jemand reproduzieren, dass Visual C++ strammere Kompilate erzeugt, wenn man sichere Destruktoren mit
throw() dekoriert?
Ich habe
throw() und
__declspec(nothrow) letztes Jahr testweise auf über 400 sichere Funktionen angewandt, und es hatte absolut
null Effekt.
Nun dekorierte ich aus Jux zwei Destruktoren, die externe (aber sichere) Funktionen aufrufen damit – und bekam 1 % kleineren Code … überall sonst nützt es aber auch weiterhin nichts … und ich habe auch nicht wirklich Lust, wieder durch die Assembly zu steigen, was genau da optimiert wird …
… ein wenig merkwürdig kommt mir das vor, weil der Compiler mit
/EHsc arbeitet, wozu die Doku
sagt:
„catches C++ exceptions only and tells the compiler to assume that extern C functions never throw a C++ exception.“ Aber wäre ja nicht das erste Mal, dass Destruktoren nachlässig verarbeitet werden …
Re: Is it just me, or …
Verfasst: 26.11.2010, 04:10
von Krishty
Eine interessante Optimierung ist es auch, die Anzahl der Funktionsparameter versteckt gering zu halten. Ich hatte beispielsweise so eine Funktion:
void render(
CGPU & GPU,
CMatrix4x4 const & world,
CMatrix4x4 const & view,
CMatrix4x4 const & projection,
float const starLuminanceFactor,
float const fieldOfView,
float const horizontalResolution
) {
updateShaderConstants(
world * view * projection,
starLuminanceFactor * horizontalResolution / (fieldOfView * fieldOfView)
);
// Lots of stuff like GPU.SetPrimitiveTopology(POINTS); here
GPU.Draw(1000);
}
Das Problem ist hier, dass sieben Parameter übergeben werden, die intern zu drei evaluieren. Hier lässt sich viel rausholen, wenn man die Parameterzahl reduziert:
void render(
CGPU & GPU,
CMatrix4x4 const & worldViewProjection,
float const relativeStarLuminanceFactor
) {
updateShaderConstants(
worldViewProjection,
relativeStarLuminanceFactor
);
// Lots of stuff like GPU.SetPrimitiveTopology(POINTS); here
GPU.Draw(1000);
}
Das macht aber die Nutzbarkeit zunichte, weil der Anwender keine Ahnung hat, wie er den relativen Wert berechnen soll. Darum deklariert man die Funktion private und fügt einen öffentlichen Wrapper mit der ursprünglichen, freundlichen Signatur hinzu:
void render(
CGPU & GPU,
CMatrix4x4 const & world,
CMatrix4x4 const & view,
CMatrix4x4 const & projection,
float const starLuminanceFactor,
float const fieldOfView,
float const horizontalResolution
) {
return render(
world * view * projection,
starLuminanceFactor * horizontalResolution / (fieldOfView * fieldOfView)
);
}
Da die Komplexität des Wrappers recht gering ist, wird der Compiler ihn überall inlinen; damit wird die Berechnung der endgültigen Parameter zum Aufrufer der Funktion verschoben. Der Aufrufer erledigt nun also scheinbar mehr Arbeit als zuvor.
Da die Parameterzahl der finalen Funktion aber jetzt mit drei statt sieben relativ niedrig ist, kann der Compiler alle Parameter in Registern übergeben. Vorher bedeutete ein Funktionsaufruf: Parameter auf den Stack schaufeln – Aufruf – Abziehen der Parameter – Rechnen. Nun bedeutet ein Funktionsaufruf: Rechnen – Aufruf. Und da die Werte, mit denen gerechnet wird, mit großer Wahrscheinlichkeit im Kontext zum Aufrufer stehen, kann da nochmal optimiert werden.
Das alles funktioniert nur, wenn globale Optimierungen aktiviert sind (sonst kann der Compiler die Parameterübergabe nicht automatisch bestimmen), die Berechnung der Parameter leicht genug für Inlining und die aufgerufene Funktion zu schwer für Inlining ist, und wenn man die Parameterzahl niedrig genug für eine Übergabe ohne Stack bekommt. Kann sich dann aber lohnen – ich hatte gerade einen Fall, wo mir das beim Aufrufer und in der finalen Funktion zusammen 40 Befehle gespart hat. Und bei Gleitkommazahlen ist der Weg FPU-/SSE-Register -> Stack -> FPU-/SSE-Register ja besonders teuer.
Nur so als Tipp. Und Code-Tags benutze ich nicht, weil ich das Scrollen scheiße finde.
Re: Is it just me, or …
Verfasst: 26.11.2010, 10:10
von CodingCat
Ich hab mal einen Code-Ansicht-Erweitern-Link eingebaut.
Re: Is it just me, or …
Verfasst: 19.12.2010, 16:30
von Krishty
Ein hübscher versteckter Fallstrick für den Optimizer sind Wirkungen in den Konstruktoren von Return-Values:
Code: Alles auswählen
// Gibt "1 KiB, 1 B" für 1025 zurück
string stringFromByteSize(
unsigned long long const size
) {
// Damit für 0 kein leerer String zurückgegeben wird
if(0 == size)
return "0 B";
char temp[sizeof("15 EiB, 1023 PiB, 1023 TiB, 1023 GiB, 1023 MiB, 1023 KiB, 1023 B ")];
// Hier wird temp befüllt
return string(temp);
}
Bei mir hat der Compiler den K’tor von
string geinlinet, und zwar in allen beiden
return-Anweisungen. Nachdem ich den Code so modifiziert habe, dass der K’tor nur noch einmal aufgerufen wird:
Code: Alles auswählen
char temp[sizeof("15 EiB, 1023 PiB, 1023 TiB, 1023 GiB, 1023 MiB, 1023 KiB, 1023 B ")];
if(0 == size) {
strcpy(temp, "0 B");
} else {
// Hier wird temp befüllt
}
return string(temp);
ist eine Menge Konstruktorkram rausgeflogen, der Registerdruck gesunken und es gibt eine Stelle weniger, an der eine Exception geschmissen werden könnte – unter’m Strich ist fast die Hälfte der Funktion weggefallen. Also immer ein Auge offen halten, wenn eine Funktion unterschiedliche Pfade zur Konstruktion eines Rückgabewerts hat.
Re: Is it just me, or …
Verfasst: 09.04.2011, 13:45
von Krishty
Kann mir das hier jemand erklären?
Code: Alles auswählen
class CNonCopyable {
private:
CNonCopyable(CNonCopyable const &);
public:
explicit CNonCopyable(int) { }
};
CNonCopyable arrayA[] = { CNonCopyable(0) }; // ERROR: copy constructor is inaccessable
struct CIndirectlyNonCopyable
: public CNonCopyable
{
explicit CIndirectlyNonCopyable(int x) : CNonCopyable(x) { }
};
CIndirectlyNonCopyable arrayB[] = { CIndirectlyNonCopyable(0) }; // OK
Gibt es bei Array-Initialisierung tatsächlich einen Unterschied dazwischen, ob ein Kopierk’tor nicht verfügbar oder nicht automatisch generiert ist? Warum versucht der, das Array per Kopierk’tor zu initialisieren, falls einer existiert?
Re: Is it just me, or …
Verfasst: 12.04.2011, 10:51
von eXile
Kann dein „OK“ gerade nicht nachvollziehen:
http://codepad.org/kDsz15IB
Re: Is it just me, or …
Verfasst: 12.04.2011, 10:56
von Krishty
Na toll, also wieder eine Microsoft-Erweiterung. Aua.
Wie ruft man bei Array-Initialisierungen K’toren explizit auf, ohne Kopien zu erzwingen?
Re: Is it just me, or …
Verfasst: 01.05.2011, 15:25
von Krishty
Häh
Warum ergibt die Negierung von
short ein
int?
Re: Is it just me, or …
Verfasst: 01.05.2011, 15:29
von Aramis
Weil die unaeren + und --Operatoren immer int zurueckgeben.
Manche Fanatiker preisen das sogar als tolle Sprachfeature an: decltype(+'a')==int
Re: Is it just me, or …
Verfasst: 01.05.2011, 15:31
von Krishty
Auch bei signed long long?