[C++] Snippets
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
[C++] Snippets
Ich habe mir vorgenommen, in nächster Zeit mal meine wichtigsten C++ Snippets zu sammeln und möglichst von Abhängigkeiten zu befreien. Der Anfang findet sich hier. Am Ende kommt hoffentlich eine nützliche und universell einsetzbare Kollektion zusammen, die sich ohne Weiteres in jedes Projekt einfügt.
Für Vorschläge, Verbesserungen, Fragen etc. ist dieser Thread gedacht.
Für Vorschläge, Verbesserungen, Fragen etc. ist dieser Thread gedacht.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Re: [C++] Snippets
Würd dann auch direkt mal meinen Senf dazugeben: Einfache Möglichkeit Methoden/Scopes per Mutex zu synchronisieren ohne bei jedem if-branch mit return ein unlock aufrufen zu müssen.
Code: Alles auswählen
// Header
#include <mutex>
class LockSection {
std::mutex* mutex;
public:
LockSection(std::mutex* m);
~LockSection();
};
// Cpp
LockSection::LockSection(std::mutex* m) {
mutex = m;
mutex->lock();
}
LockSection::~LockSection() {
mutex->unlock();
}
Code: Alles auswählen
class Foo {
std::mutex lockObject;
public:
void foo() {
LockSection section(&lockObject);
if(...) {
...
return;
}
...
}
void bar() {
...
{
LockSection section(&lockMutex);
...
}
...
}
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: [C++] Snippets
Sehr schön, so habe ich mir das vorgestellt. Zwar wird das bereits durch std::lock_guard und std::unique_lock abgedeckt, aber erstens werden wir uns dessen erst dadurch bewusst und zweitens kann man gerade durch den Vergleich zu den Standardimplementierungen viel lernen. Verbesserungsvorschläge:
Deine Klasse sollte unbedingt Kopie und Zuweisung von LockSection-Instanzen verbieten, weil dadurch Locks ggf. nie mehr freigegeben oder aber doppelt freigegeben werden können. Das geht z.B. durch Verstecken von Kopierkonstruktor und Zuweisungsoperator im private-Sichtbarkeitsbereich:
Weiterhin wäre es wohl geschickt, das Mutex per Referenz entgegenzunehmen, um die Gültigkeit des übergebenen Zeigers zu erzwingen. Tatsächlich haben die meisten Compiler zwar auch keine Probleme mit Null-Referenzen, aber die Dereferenzierung geschieht dann auf Aufruferseite, d.h. der Aufrufer ist schuld. ;) Alternativ ein assert(m != nullptr).
Deine Klasse sollte unbedingt Kopie und Zuweisung von LockSection-Instanzen verbieten, weil dadurch Locks ggf. nie mehr freigegeben oder aber doppelt freigegeben werden können. Das geht z.B. durch Verstecken von Kopierkonstruktor und Zuweisungsoperator im private-Sichtbarkeitsbereich:
Code: Alles auswählen
private:
LockSection(const LockSection &); // Müssen nicht implementiert werden, da niemals aufgerufen
LockSection& operator =(const LockSection &);
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
- Schrompf
- Moderator
- Beiträge: 5045
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: [C++] Snippets
Das könnte man verallgemeinern auf alle möglichen Aufräum-Sachen. Habe ich schon oft gesehen, aber noch nie selbst verwendet. Sowas in dem Stil:
Das ist jetzt frei zusammengetippt, ich weiß ehrlich gesagt nicht, ob das so funktionieren würde. Aber es war eine spontane Idee.
Code: Alles auswählen
template <typename DoIt>
struct OnCleanUp
{
DoIt doIt;
OnCleanUp( DoIt doit) : doIt( doit) { }
~OnCleanUp() { doIt(); }
};
// Nutzungsbeispiel. Bitte keine Bemerkungen zu scoped_ptr und Konsorten, es ist nur ein Beispiel
void Bla()
{
Irgendwas* iw = new Irgendwas();
auto iw_cleanup = OnCleanUp( [=]() { delete iw; } );
if( false )
return; // hier wird automatisch iw gelöscht
}
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: [C++] Snippets
Ja, habe ich mir auch schon gebastelt, dann aber nie verwendet. Letztlich liegt der große Vorteil von spezifischeren Strukturen darin, dass man sich um das Aufräumen überhaupt keine Gedanken machen muss und insbesondere im Geltungsbereich auch nur ein Objekt hat. Das Anlegen und/oder Verwalten von Objekten wird so rein deklarativ. Sobald man mehrere Objekte, Deklarationen und Anweisungen hat, muss man sich hingegen wieder Gedanken um die Reihenfolge, Ausnahmesicherheit etc. machen.
Ich habe auch schon noch wesentlich abstraktere Konstrukte gesehen, in denen der Guard zu einem Template mit Guard-Traits wurde. Diese Idee ist einerseits nett, weil das Schreiben eines sicheren und vollständigen Guards, wie im com_ptr-Beispiel zu sehen, alles andere als trivial ist. Andererseits kann dieser Abstraktionsgrad auch problematisch werden, weil dann an der Schnittstelle zu den Traits wieder Garantien erforderlich werden, die eventuell nicht ganz leicht zu überblicken sind.
Ich habe auch schon noch wesentlich abstraktere Konstrukte gesehen, in denen der Guard zu einem Template mit Guard-Traits wurde. Diese Idee ist einerseits nett, weil das Schreiben eines sicheren und vollständigen Guards, wie im com_ptr-Beispiel zu sehen, alles andere als trivial ist. Andererseits kann dieser Abstraktionsgrad auch problematisch werden, weil dann an der Schnittstelle zu den Traits wieder Garantien erforderlich werden, die eventuell nicht ganz leicht zu überblicken sind.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Re: [C++] Snippets
Sowas gibt es übrigens in der BOOST-Library fest eingebaut. Nennt sich scoped_mutex. Nur falls die jemand eh schon benutzt :)RazorX hat geschrieben:Würd dann auch direkt mal meinen Senf dazugeben: Einfache Möglichkeit Methoden/Scopes per Mutex zu synchronisieren ohne bei jedem if-branch mit return ein unlock aufrufen zu müssen.
- kimmi
- Moderator
- Beiträge: 1405
- Registriert: 26.02.2009, 09:42
- Echter Name: Kim Kulling
- Wohnort: Luebeck
- Kontaktdaten:
Re: [C++] Snippets
Tu ich und das hat sich ausgezahlt :). Danke für die Snippets, da kann man sich noch was abschauen.
Gruß Kimmi
Gruß Kimmi
Re: [C++] Snippets
Auf der Arbeit wird ein Projekt (mittlerweile fast 20 Jahre alt) mit MFC umgesetzt und da schließt sich der BOOST-Threading Teil aus. Sobald man dieses dazulinkt, sind auf magische Art und Weise alle möglichen MFC States zerschossen.Andre hat geschrieben:Sowas gibt es übrigens in der BOOST-Library fest eingebaut. Nennt sich scoped_mutex. Nur falls die jemand eh schon benutzt :)RazorX hat geschrieben:Würd dann auch direkt mal meinen Senf dazugeben: Einfache Möglichkeit Methoden/Scopes per Mutex zu synchronisieren ohne bei jedem if-branch mit return ein unlock aufrufen zu müssen.
Re: [C++] Snippets
Ich hatte mir für COM interfaces mal eine smartptr Klasse geschrieben, hatte aber oft das Problem, dass ein inkompatibler Typ den Fehler nur in der Klasse angezeigt hat, nicht aber an der Stelle wo die Zuweisung stattfand. Nun bin ich mal über std::enable_if gestolpert.
Sehr lesbar ist es nicht mehr, funktioniert aber super. Das ganze basiert auf folgendem C++ Prinzip http://en.wikipedia.org/wiki/Substituti ... t_an_error.
Code: Alles auswählen
template<typename comT>
class com_ptr {
comT* pData;
//...
public:
static_assert(std::is_base_of<IUnknown, comT>::value, "Template argument comT must be inherited from COM IUnknown interface!");
com_ptr(comT* pObj = nullptr);
com_ptr(const com_ptr& pObj);
template<typename comT2>
com_ptr(comT2* pObj, typename std::enable_if<std::is_base_of<comT, comT2>::value>::type* = nullptr);
template<typename comT2>
com_ptr(const com_ptr<comT2>& pObj, typename std::enable_if<std::is_base_of<comT, comT2>::value>::type* = nullptr);
template<typename comT2>
com_ptr(com_ptr<comT2>&& pObj, typename std::enable_if<std::is_base_of<comT, comT2>::value>::type* = nullptr);
template<typename comT2>
typename std::enable_if<std::is_base_of<comT, comT2>::value, com_ptr>::type& operator = (const com_ptr<comT2>& pObj);
template<typename comT2>
typename std::enable_if<std::is_base_of<comT, comT2>::value, com_ptr>::type& operator = (com_ptr<comT2>&& pObj);
// ...
};
- dot
- Establishment
- Beiträge: 1745
- Registriert: 06.03.2004, 18:10
- Echter Name: Michael Kenzel
- Kontaktdaten:
Re: [C++] Snippets
Ist das denn so überhaupt erlaubt? COM kennt afaik nur Interfaces und ein Objekt kann verschiedene Interfaces implementieren, aber keine Ableitungsbeziehungen...
Re: [C++] Snippets
Zumindest in der MSDN steht auch immer brav geschrieben von welchen COM Interfaces die einzelnen Interfaces erben.
Beispiel: ID3D11Texture2D -> ID3D11Resource -> ID3D11DeviceChild -> IUnknown
Beispiel: ID3D11Texture2D -> ID3D11Resource -> ID3D11DeviceChild -> IUnknown
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Snippets
Das ist eine Vererbungsbeziehung im COM-Kontext; nicht im C++-Kontext. Die MSDN ist ja nicht C++-spezifisch. Beides fällt nur zufällig mit Visual C++’ Implementierung virtueller Funktionen übereinander.
Ich kann mich erinnern, dass die Direct3D-9-Header noch Vererbung für COM eingesetzt hatten; ab Direct3D 10 hatten sie die dann komplett entfernt.
Ich kann mich erinnern, dass die Direct3D-9-Header noch Vererbung für COM eingesetzt hatten; ab Direct3D 10 hatten sie die dann komplett entfernt.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Snippets
Ich spucke hier auch mal meinen Kram hin:
TO-DO-Markierungen für Visual C++ in Quelltext
Benutzung:
TODO("get shit done");
erzeugt eine anklickbare Meldung in Visual C++’ Ausgabefenster.
Besondere Gleitkommawerte:
(nur mit Visual C++ getestet) (Erläuterungen)
Bzw. die double-Versionen:
Kompilierdatum und -Uhrzeit in ISO 8601-Form
TO-DO-Markierungen für Visual C++ in Quelltext
Benutzung:
TODO("get shit done");
erzeugt eine anklickbare Meldung in Visual C++’ Ausgabefenster.
Code: Alles auswählen
#define TODO_INTERNAL_STRINGIZE(text) #text
#define TODO_INTERNAL_QUOTE(text) TODO_INTERNAL_STRINGIZE(text)
#define TODO(toDoText) __pragma(message(__FILE__" ("TODO_INTERNAL_QUOTE(__LINE__)"): TODO: "toDoText))
Besondere Gleitkommawerte:
(nur mit Visual C++ getestet) (Erläuterungen)
Code: Alles auswählen
#if defined _MSC_VER
// Visual C++ won't optimize symbolic constants properly. Therefore, any constant needs to be hard-coded and written out
// explicitly. For special values like NaN and infinity, this may cause floating-point overruns. Since this is well
// desired, the according warning 4056 is disabled.
# pragma warning(push)
# pragma warning(disable: 4056)
#endif
float const smallest = 1.17549436e-38f; // 0x00800000
float const greatest = 1.0842022e-19f; // 0x20000000
float const squareRootOfSmallest = 3.4028234e38f; // 0x7F7FFFFF
float const squareRootOfGreatest = 1.8446744e19f; // 0x5F800000
float const positiveInfinity = 3.4028234e38f * 2.0f;
float const negativeInfinity = 3.4028234e38f * -2.0f;
float const NaN = 3.4028234e38f * 2.0f * 0.0f;
float const pi = 3.1415926535f;
#if defined _MSC_VER
# pragma warning(pop)
#endif
Code: Alles auswählen
double const smallest = 2.2250738585072014e-308; // 0x0010000000000000
double const greatest = 1.4916681462400413e-154; // 0x2000000000000000
double const squareRootOfSmallest = 1.7976931348623157e308; // 0x7FEFFFFFFFFFFFFF
double const squareRootOfGreatest = 1.3407807929942598e154; // 0x5FF0000000000000
double const positiveInfinity = 1.7976931348623157e308 * 2.0;
double const negativeInfinity = 1.7976931348623157e308 * -2.0;
double const NaN = 1.7976931348623157e308 * 2.0 * 0.0;
double const pi = 3.1415926535897932384626433832795;
Kompilierdatum und -Uhrzeit in ISO 8601-Form
Code: Alles auswählen
// Compilation date and time as a zero-terminated ASCII string in the format "YYYY-MM-DD hh:mm" (Seconds are useless because
// there will not be any deployments within the same minute).
#if defined _MSC_VER
// Visual C++ has several problems regarding '__DATE__' and '__TIME__'. The strings are usually not statically evaluated
// until they are copied. Then, they are still not constant expressions. Any variable using them is evaluated statically
// only in the very first indirection. This makes dedicated code necessary.
// Tested with Visual C++ 2012 for x64.
// Force static evaluation in Visual C++ by copying the literals:
namespace {
static char const time[] = __TIME__;
static char const date[] = __DATE__;
}
extern char const buildDateAndTime[] = {
// YYYY
date[ 7],
date[ 8],
date[ 9],
date[10],
'-',
// Literals are evaluated statically only for the first indirection — i.e., the comparison must take place right here.
// The first character of month is '0' for October, November, and December.
(date[0] == 'O' || date[0] == 'N' || date[0] == 'D') ? '1' : '0',
// The second character is
// '1' for January (don't confuse with June or Juli) or November;
// '2' for February or December;
// '3' for March (don't confuse with May);
// …
((date[0] == 'J' && date[1] == 'a') || date[0] == 'N') ? '1' :
(date[0] == 'F' || date[0] == 'D') ? '2' :
(date[0] == 'M' && date[1] == 'a' && date[2] == 'r') ? '3' :
(date[0] == 'A' && date[1] == 'p') ? '4' :
(date[0] == 'M' && date[1] == 'a' && date[2] == 'y') ? '5' :
(date[0] == 'J' && date[1] == 'u' && date[2] == 'n') ? '6' :
(date[0] == 'J' && date[1] == 'u' && date[2] == 'l') ? '7' :
(date[0] == 'A' && date[1] == 'u') ? '8' :
(date[0] == 'S') ? '9' :
'0',
'-',
// DD
' ' == date[4] ? '0' : date[4],
date[5],
' ',
// hh
time[0],
time[1],
':',
// mm
time[3],
time[4],
'\0'
};
#else
char const buildDateAndTime[] = {
// YYYY
__DATE__[ 7],
__DATE__[ 8],
__DATE__[ 9],
__DATE__[10],
'-',
// The first character of month is '0' for October, November, and December.
(__DATE__[0] == 'O' || __DATE__[0] == 'N' || __DATE__[0] == 'D') ? '1' : '0',
// The second character is
// '1' for January (don't confuse with June or Juli) or November;
// '2' for February or December;
// '3' for March (don't confuse with May);
// ...
((__DATE__[0] == 'J' && __DATE__[1] == 'a') || __DATE__[0] == 'N') ? '1' :
(__DATE__[0] == 'F' || __DATE__[0] == 'D') ? '2' :
(__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r') ? '3' :
(__DATE__[0] == 'A' && __DATE__[1] == 'p') ? '4' :
(__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y') ? '5' :
(__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n') ? '6' :
(__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l') ? '7' :
(__DATE__[0] == 'A' && __DATE__[1] == 'u') ? '8' :
(__DATE__[0] == 'S') ? '9' :
'0',
'-',
// DD
' ' == __DATE__[4] ? '0' : __DATE__[4],
__DATE__[5],
' ',
// hh
__TIME__[0],
__TIME__[1],
':',
// mm
__TIME__[3],
__TIME__[4],
'\0'
};
#endif
Zuletzt geändert von Krishty am 01.05.2013, 21:56, insgesamt 1-mal geändert.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Snippets
Eine Datei unter Windows in den Speicher mappen:
Nicht so kurz und nicht ganz ohne Abhängigkeiten, aber die einfachste Methode ohne Luxus:Wie man sieht beruht die Einfachheit darauf, die Datei nur über die Basisadresse zu halten und die überflüssigen anderen Handles so früh wie möglich wieder zu schließen. Gegenüber einer naiven Lösung dürfte das 3,5 KiB Maschinentext und Ausnahmebehandlungsroutinen sparen (also fast eine Seite).
Außerdem lässt sich das in wenigen Zeilen in RAII abbilden:Mich persönlich interessiert nur, dass eine Datei nicht verfügbar ist; nicht, warum. Wer eine Schwäche für sowas hat kann die drei zusätzlichen Ausnahmen noch einprogrammieren. Weil alle meine Algorithmen über Ranges laufen und die Klasse 99 % der Dateien geladen kriegt, hat sie mir bisher gute Dienste geleistet:
ReadableMappedFile foo(L"bar.txt");
Nicht so kurz und nicht ganz ohne Abhängigkeiten, aber die einfachste Methode ohne Luxus:
Code: Alles auswählen
#include <Windows.h>
template <
typename Element
> struct Range {
Element * begin;
Element * end;
};
// Maps the file at the given, zero-terminated path for reading. The beginning of the result is the base address which
// is required to unmap the file.
Range<unsigned char const> const mapForReading(wchar_t const * const toItsZeroTerminatedPath) {
// The general procedure is:
// 1) Open the file;
// 2) obtain the file's size;
// 3) create the file mapping object;
// 4) map the file to memory.
// There is no need to carry the handles through the rest of the program:
// "Although an application may close the file handle used to create a file mapping object, the system holds
// the corresponding file open until the last view of the file is unmapped."
// (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366882)
// Therefore, once the file mapping object is created, the file is closed. Once the file is mapped, the file mapping
// object is closed. (This will also save error handling code because in the case of an error, these objects needed
// to be closed anyway.)
Range<unsigned char const> result;
auto const filesHandle = CreateFileW(
toItsZeroTerminatedPath,
GENERIC_READ,
FILE_SHARE_READ,
nullptr,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
nullptr
);
if(INVALID_HANDLE_VALUE != filesHandle) {
LARGE_INTEGER size;
if(0 != GetFileSizeEx(filesHandle, &size)) {
auto const fileMapsHandle = CreateFileMappingW(filesHandle, nullptr, PAGE_READONLY, 0u, 0u, nullptr);
CloseHandle(filesHandle);
if(nullptr != fileMapsHandle) {
result.begin = reinterpret_cast<unsigned char *>(MapViewOfFile(fileMapsHandle, FILE_MAP_READ, 0u, 0u, 0u));
CloseHandle(fileMapsHandle);
if(nullptr != result.begin) {
result.end = result.begin + size.QuadPart;
return result;
}
}
}
}
throw std::exception();
}
Außerdem lässt sich das in wenigen Zeilen in RAII abbilden:
Code: Alles auswählen
class ReadableMappedFile {
public:
ReadableMappedFile(wchar_t const * const toItsZeroTerminatedPath)
: myBytes(mapForReading(toItsZeroTerminatedPath))
{ }
Range<unsigned char const> const & bytes() const {
return myBytes;
}
~ReadableMappedFile() {
UnmapViewOfFile(myBytes.begin);
}
private:
Range<unsigned char const> myBytes;
};
ReadableMappedFile foo(L"bar.txt");
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: [C++] Snippets
arraylen-Update für statisch referenzierte Members:
Ermöglicht:
Irgendwelche Einwände bezüglich &(a) im Makro?
Code: Alles auswählen
namespace helper
{
template <class T, size_t S> char (&arraylen_helper(T (*const a)[S]))[S];
template <class C, class T, size_t S> char (&arraylen_helper(T (C::*a)[S]))[S];
}
#define arraylen(a) sizeof(::helper::arraylen_helper(&(a)))
Code: Alles auswählen
struct foo { int bar[5]; };
arraylen(foo::bar)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Re: [C++] Snippets
Naja, wenn man nur böswillig genug ist, kriegt man es immer kaputt:
Code: Alles auswählen
#include <iostream>
namespace helper
{
template <class T, size_t S> char (&arraylen_helper(T (*const a)[S]))[S];
template <class C, class T, size_t S> char (&arraylen_helper(T (C::*a)[S]))[S];
}
#define arraylen(a) sizeof(::helper::arraylen_helper(&(a)))
int main(int argc, char * argv[])
{
struct foo
{
int (*(&operator&()))[10]
{
static int (*gna)[10];
return gna;
}
} bar;
// Sollte Fehler ausgeben
std::cout << arraylen(bar) << std::endl;
return 0;
}
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Snippets
Debug-Hilfen für die alte WinAPI (haben mir in einer Handvoll Fälle Debugging erspart):
bool isWindowHandle_DEBUG(
HWND const suspect
) {
return 0 != IsWindow(suspect);
}
bool isChild_DEBUG(
HWND const window
) {
assert(isWindowHandle_DEBUG(window));
return 0 != (WS_CHILD & GetWindowLong(window, GWL_STYLE));
}
bool isDialogHandle_DEBUG(
HWND const suspect
) {
assert(isWindowHandle_DEBUG(suspect));
// For each dialog, the name of its window class is "#32770". This seems like an ugly non-standard hack, but
// it is actually documented behaviour: MSDN — "About Window Classes".
UTF16Unit className[8];
GetClassNameW(suspect, className, 7);
if(0 != wcscmp(className, L"#32770")) {
return false;
}
return true;
}
bool controlExistsInDialog_DEBUG(
HWND const dialog,
WORD const controlID
) {
assert(isDialogHandle_DEBUG(dialog));
return nullptr != GetDlgItem(dialog, controlID);
}
bool isMenuHandle_DEBUG(
HMENU const menu
) {
return 0 != IsMenu(menu);
}
bool itemExistsInMenu_DEBUG(
HMENU const menu,
WORD const id
) {
assert(isMenuHandle_DEBUG(menu));
MENUITEMINFO info = { };
info.cbSize = sizeof info;
return 0 != GetMenuItemInfo(menu, id, FALSE, &info);
}
Assertions für WinAPI-Aufrufe kann man mit allen Funktionen benutzen, für die die MSDN sowas sagt wie:
If the function fails, the return value is zero. To get extended error information, call GetLastError.
indem man schreibt:
WINAPI_ASSERT(DestroyWindow(hwnd));
#if defined _DEBUG
bool shouldIgnoreWinAPIError(
char const * toSourceFilesName,
int sourceFilesLine // '__LINE__' isn't 'unsigned int' m[
);
# define WINAPI_ASSERT(call) void((0 != call) || shouldIgnoreWinAPIError(__FILE__, __LINE__) || (__debugbreak(), false))
#else
# define WINAPI_ASSERT(call) call
#endif
bool shouldIgnoreWinAPIError(
char const * const toSourceFilesName,
int const sourceFilesLine
) {
auto const errorID = GetLastError();
// • Let Windows allocate the message's memory by passing the 'FORMAT_MESSAGE_ALLOCATE_BUFFER' flag, the address of a
// pointer for 'lpBuffer', and a size of zero. "The caller should use the LocalFree function to free the buffer when
// it is no longer needed."
// • The error was a system error, so the error message should be searched in system files. Therefore, pass
// 'FORMAT_MESSAGE_FROM_SYSTEM'.
// • Neither do we know what message will come, nor do we know which parameters are expected for formatting. Therefore,
// do not process placeholders by passing the 'FORMAT_MESSAGE_IGNORE_INSERTS' flag.
// • Do not pass a preferred language (instead, zero). This makes the function search for errors in the following order:
// 1. Language neutral
// 2. Thread LANGID, based on the thread's locale value
// 3. User default LANGID, based on the user's default locale value
// 4. System default LANGID, based on the system default locale value
// 5. US English
char * toZeroTerminatedErrorMessage;
if(0 == FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
errorID,
0,
reinterpret_cast<char *>(&toZeroTerminatedErrorMessage), 0,
nullptr
)) {
__debugbreak(); // Could not retrieve last WinAPI error!
return true;
}
char textBuffer[256 + 3 + 128 * 1024];
// First, print a message to the debugger's output window, as this is mostly fail-safe. Mind the format:
// <filename> (<line number>): WinAPI error:
// <message>
// because this will enable Visual C++ users to double-click the assertion text and immediately open the corresponding
// source file. See MSBuild Team Blog — "MSBuild / Visual Studio aware error messages and message formats".
sprintf(textBuffer,
"\n"
"%s (%u): WinAPI error:\n"
" %s\n",
toSourceFilesName, unsigned(sourceFilesLine), toZeroTerminatedErrorMessage
);
OutputDebugStringA(textBuffer);
// Show the message box.
sprintf(textBuffer,
"in %s (%u):\n"
"\n"
"%s\n"
"(press 'retry' to debug)",
toSourceFilesName, unsigned(sourceFilesLine), toZeroTerminatedErrorMessage
);
LocalFree(toZeroTerminatedErrorMessage);
switch(MessageBoxA(
nullptr,
textBuffer,
"WinAPI error",
MB_ABORTRETRYIGNORE
| MB_ICONERROR
| MB_SETFOREGROUND
| MB_TASKMODAL // deactivate all other windows on the thread
)) {
case IDABORT:
abort();
case IDRETRY:
return false; // break into the debugger
case IDIGNORE:
return true; // proceed
default:
// If the process is shutting down, Windows won't allow any new windows. This will make the message box fail,
// and in this case the best option is to break into the debugger (NOT to abort like MFC's 'ASSERT()' does!).
return false;
}
}
Natürlich erspart das in den meisten Fällen keine Fehlerbehandlung.
bool isWindowHandle_DEBUG(
HWND const suspect
) {
return 0 != IsWindow(suspect);
}
bool isChild_DEBUG(
HWND const window
) {
assert(isWindowHandle_DEBUG(window));
return 0 != (WS_CHILD & GetWindowLong(window, GWL_STYLE));
}
bool isDialogHandle_DEBUG(
HWND const suspect
) {
assert(isWindowHandle_DEBUG(suspect));
// For each dialog, the name of its window class is "#32770". This seems like an ugly non-standard hack, but
// it is actually documented behaviour: MSDN — "About Window Classes".
UTF16Unit className[8];
GetClassNameW(suspect, className, 7);
if(0 != wcscmp(className, L"#32770")) {
return false;
}
return true;
}
bool controlExistsInDialog_DEBUG(
HWND const dialog,
WORD const controlID
) {
assert(isDialogHandle_DEBUG(dialog));
return nullptr != GetDlgItem(dialog, controlID);
}
bool isMenuHandle_DEBUG(
HMENU const menu
) {
return 0 != IsMenu(menu);
}
bool itemExistsInMenu_DEBUG(
HMENU const menu,
WORD const id
) {
assert(isMenuHandle_DEBUG(menu));
MENUITEMINFO info = { };
info.cbSize = sizeof info;
return 0 != GetMenuItemInfo(menu, id, FALSE, &info);
}
Assertions für WinAPI-Aufrufe kann man mit allen Funktionen benutzen, für die die MSDN sowas sagt wie:
If the function fails, the return value is zero. To get extended error information, call GetLastError.
indem man schreibt:
WINAPI_ASSERT(DestroyWindow(hwnd));
#if defined _DEBUG
bool shouldIgnoreWinAPIError(
char const * toSourceFilesName,
int sourceFilesLine // '__LINE__' isn't 'unsigned int' m[
);
# define WINAPI_ASSERT(call) void((0 != call) || shouldIgnoreWinAPIError(__FILE__, __LINE__) || (__debugbreak(), false))
#else
# define WINAPI_ASSERT(call) call
#endif
bool shouldIgnoreWinAPIError(
char const * const toSourceFilesName,
int const sourceFilesLine
) {
auto const errorID = GetLastError();
// • Let Windows allocate the message's memory by passing the 'FORMAT_MESSAGE_ALLOCATE_BUFFER' flag, the address of a
// pointer for 'lpBuffer', and a size of zero. "The caller should use the LocalFree function to free the buffer when
// it is no longer needed."
// • The error was a system error, so the error message should be searched in system files. Therefore, pass
// 'FORMAT_MESSAGE_FROM_SYSTEM'.
// • Neither do we know what message will come, nor do we know which parameters are expected for formatting. Therefore,
// do not process placeholders by passing the 'FORMAT_MESSAGE_IGNORE_INSERTS' flag.
// • Do not pass a preferred language (instead, zero). This makes the function search for errors in the following order:
// 1. Language neutral
// 2. Thread LANGID, based on the thread's locale value
// 3. User default LANGID, based on the user's default locale value
// 4. System default LANGID, based on the system default locale value
// 5. US English
char * toZeroTerminatedErrorMessage;
if(0 == FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
errorID,
0,
reinterpret_cast<char *>(&toZeroTerminatedErrorMessage), 0,
nullptr
)) {
__debugbreak(); // Could not retrieve last WinAPI error!
return true;
}
char textBuffer[256 + 3 + 128 * 1024];
// First, print a message to the debugger's output window, as this is mostly fail-safe. Mind the format:
// <filename> (<line number>): WinAPI error:
// <message>
// because this will enable Visual C++ users to double-click the assertion text and immediately open the corresponding
// source file. See MSBuild Team Blog — "MSBuild / Visual Studio aware error messages and message formats".
sprintf(textBuffer,
"\n"
"%s (%u): WinAPI error:\n"
" %s\n",
toSourceFilesName, unsigned(sourceFilesLine), toZeroTerminatedErrorMessage
);
OutputDebugStringA(textBuffer);
// Show the message box.
sprintf(textBuffer,
"in %s (%u):\n"
"\n"
"%s\n"
"(press 'retry' to debug)",
toSourceFilesName, unsigned(sourceFilesLine), toZeroTerminatedErrorMessage
);
LocalFree(toZeroTerminatedErrorMessage);
switch(MessageBoxA(
nullptr,
textBuffer,
"WinAPI error",
MB_ABORTRETRYIGNORE
| MB_ICONERROR
| MB_SETFOREGROUND
| MB_TASKMODAL // deactivate all other windows on the thread
)) {
case IDABORT:
abort();
case IDRETRY:
return false; // break into the debugger
case IDIGNORE:
return true; // proceed
default:
// If the process is shutting down, Windows won't allow any new windows. This will make the message box fail,
// and in this case the best option is to break into the debugger (NOT to abort like MFC's 'ASSERT()' does!).
return false;
}
}
Natürlich erspart das in den meisten Fällen keine Fehlerbehandlung.
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: [C++] Snippets
Zwei verallgemeinernde Schleifenmuster, die mir elegant erscheinen:
Man beachte, dass keine Negationen oder Vergleiche eingefügt werden. Beide Muster sollten in den meisten (allen?) Fällen optimalen Code generieren.
Code: Alles auswählen
// Variante 1 (geschachtelt)
while (true)
{
// mehr Variablen, Berechnungen ...
if (Bedingung1)
{
// mehr Variablen, Berechnungen ...
if (Bedingung2)
{
// ...
continue;
}
}
break;
}
Code: Alles auswählen
// Variante 2 (linear)
#define loop while (true)
#define loop_while(...) if (__VA_ARGS__) (void) 0; else break
loop
{
// mehr Variablen, Berechnungen ...
loop_while (Bedingung1);
// mehr Variablen, Berechnungen ...
loop_while (Bedingung2);
// ...
}
Zuletzt geändert von CodingCat am 20.06.2014, 11:57, insgesamt 1-mal geändert.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
- kimmi
- Moderator
- Beiträge: 1405
- Registriert: 26.02.2009, 09:42
- Echter Name: Kim Kulling
- Wohnort: Luebeck
- Kontaktdaten:
Re: [C++] Snippets
Allerdings sind sie nicht als defines zu erkennen. Wenn nun irgendwer eine Funktion loop_while nennt, kommst du in Teufels Küche. Und wer mir nun erzählen möchte, dass man sowas ja im Kopf haben muß: nein, Erfahrung lehrt, dass das oft schief geht. Großgeschrieben wäre das Problem nicht so da.
Gruß Kimmi
Gruß Kimmi
- CodingCat
- Establishment
- Beiträge: 1857
- Registriert: 02.03.2009, 21:25
- Wohnort: Student @ KIT
- Kontaktdaten:
Re: [C++] Snippets
Ich traue euch zu, dass ihr eure jeweiligen Namenskonventionen auch ohne meine Hilfe umgesetzt bekommt. ;) Ihr müsst überhaupt keine Makros benutzen, wenn ihr das nicht wollt; im Beispiel kommt denke ich die Bedeutung so am besten raus.kimmi hat geschrieben:Allerdings sind sie nicht als defines zu erkennen. Wenn nun irgendwer eine Funktion loop_while nennt, kommst du in Teufels Küche. Und wer mir nun erzählen möchte, dass man sowas ja im Kopf haben muß: nein, Erfahrung lehrt, dass das oft schief geht. Großgeschrieben wäre das Problem nicht so da.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Re: [C++] Snippets
Zunächst einmal danke für das Stück Code. Das hat mir bereits gute Dienste geleistet um den Überblick über die TODOs zu behalten. Ich wollte noch ein paar Ideen für Erweiterungen / Anpassungen geben. Hier mal mein aktueller Schnipsel:Krishty hat geschrieben:TO-DO-Markierungen für Visual C++ in Quelltext
Benutzung:
TODO("get shit done");
erzeugt eine anklickbare Meldung in Visual C++’ Ausgabefenster.Code: Alles auswählen
#define TODO_INTERNAL_STRINGIZE(text) #text #define TODO_INTERNAL_QUOTE(text) TODO_INTERNAL_STRINGIZE(text) #define TODO(toDoText) __pragma(message(__FILE__" ("TODO_INTERNAL_QUOTE(__LINE__)"): TODO: "toDoText))
Code: Alles auswählen
#if defined(_MSC_VER)
# define __INTERNAL_STRINGIZE_HELPER(x) #x
# define __INTERNAL_STRINGIZE(x) __INTERNAL_STRINGIZE_HELPER(x)
# define __INTERNAL_MESSAGE(text) __pragma( message(__FILE__ "(" __INTERNAL_STRINGIZE(__LINE__) ")" text) )
# define COMPILER_WARNING(text) __INTERNAL_MESSAGE( ": warning : " text )
# define COMPILER_ERROR(text) __INTERNAL_MESSAGE( ": error : " text )
# define MESSAGE(text) __INTERNAL_MESSAGE( ": " text )
# define TODO(text) COMPILER_WARNING( "TODO: " text )
#else
# define COMPILER_WARNING(text)
# define COMPILER_ERROR(text)
# define MESSAGE(text)
# define TODO(text)
#endif
Ich habe in diesem Fall das TODO als Warnung ausgegeben, weil ich es gewohnt bin, dass Compiler-Warnungen etwas sind, dem man Beachtung schenken sollte. Wem das nicht gefällt der kann einfach in der Zeile #define TODO(text) COMPILER_WARNING( "TODO: " text ) aus dem COMPILER_WARNING ein MESSAGE machen.
Ohne Input kein Output.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Snippets
Wo du es gerade erwähnst: Ich saß letztens an der Clang-Kompatibilität, bin aber nicht fertig geworden :( Für GCC und Clang sähe das Gegenstück so ähnlich wie das aus:
#define TODO_INTERNAL_DEFER(OPERAND, ...) OPERAND(__VA_ARGS__)
#define TODO(TODOTEXT) _Pragma(TODO_INTERNAL_DEFER(warning(TODOTEXT)))
Vielleicht kann, wer auf diesen Systemen entwickelt, was damit anfangen.
#define TODO_INTERNAL_DEFER(OPERAND, ...) OPERAND(__VA_ARGS__)
#define TODO(TODOTEXT) _Pragma(TODO_INTERNAL_DEFER(warning(TODOTEXT)))
Vielleicht kann, wer auf diesen Systemen entwickelt, was damit anfangen.
Re: [C++] Snippets
Arbeite leider auch nur im VS zur Zeit. Wäre aber cool wenn man das Beispiel für möglichst viele Compiler/IDEs erweitern könnte.Krishty hat geschrieben:Vielleicht kann, wer auf diesen Systemen entwickelt, was damit anfangen.
Ohne Input kein Output.
- Chromanoid
- Moderator
- Beiträge: 4273
- Registriert: 16.10.2002, 19:39
- Echter Name: Christian Kulenkampff
- Wohnort: Lüneburg
Re: [C++] Snippets
Kann man in VC++ o.Ä. Makros eigentlich vernünftig dokumentieren? Code Completion mit aufpoppender Dokumentation stelle ich mir da sehr sinnvoll vor. Ich habe neulich die "DSL Descriptors" für Groovy mit Eclipse entdeckt und finde damit sind dynamische Sprachen mit DSL Gemurkse fast schon sinnvoll benutzbar.
Zuletzt geändert von Chromanoid am 06.02.2014, 23:48, insgesamt 1-mal geändert.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Snippets
// Once upon a time, there was a little defime … defiNe … aw shit
#define FOO
#define FOO // use with BAR
Beides wird bei Autovervollständigung und bei über dem Namen schwebender Maus angezeigt.
#define FOO
#define FOO // use with BAR
Beides wird bei Autovervollständigung und bei über dem Namen schwebender Maus angezeigt.
Re: [C++] Snippets
Ich habe auf der Arbeit etwas sehr ähnliches zum Erzeugen von Compilermeldungen geschrieben. Was auch sehr nützlich ist, sich ein Makro zu schreiben, welches auf eine notwendige Lokalisierung hinweist.
Code: Alles auswählen
#define i18n COMPILER_WARNING("TODO: Lokalisierung notwendig")
foo.bar("Test" i18n);
- Chromanoid
- Moderator
- Beiträge: 4273
- Registriert: 16.10.2002, 19:39
- Echter Name: Christian Kulenkampff
- Wohnort: Lüneburg
Re: [C++] Snippets
@Krishty: Mmmh, na immerhin etwas. Erkennt der auch doxygen? Also sowas:
/**
* ZERO
* @return 0
*/
Sorry fürs offtopic, aber ich finde, wenn ihr schon Eure Makros postet, dann doch am besten gleich mit brauchbarem Kommentar oder? :D
/**
* ZERO
* @return 0
*/
Sorry fürs offtopic, aber ich finde, wenn ihr schon Eure Makros postet, dann doch am besten gleich mit brauchbarem Kommentar oder? :D
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Snippets
Visual Studio erkennt nicht Doxygen, aber einen XML-Dialekt. Ich kann den gerade nicht auswendig, aber ein Beispiel siehst du in den DirectWrite-Headern. Die Kommentare werden dann von der Autovervollständigung formatiert, den Parametern zugeordnet, und so weiter. Es gibt auch einen Compiler-Schalter, der sie beim Kompilieren automatisch in eine XML-Datei backt, von wo aus man sie weiterverwerten kann.
Für mich persönlich ist Kommentarformatierung Quelltextverschwendung; aber viele Leute stehen ja drauf.
Für mich persönlich ist Kommentarformatierung Quelltextverschwendung; aber viele Leute stehen ja drauf.
Re: [C++] Snippets
Das IntelliSense diese Kommentare unter C++ versteht, ist aber auch erst seit Visual Studio 2013 der Fall. Vorher konnte man zwar auch die Kommentare schreiben und per Compiler in eine XML-Datei backen, aber IntelliSense hat den gesamten Inhalt unformatiert wiedergegeben.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: [C++] Snippets
2012 :-) Unter Umständen war es auch schon in Visual Studio 2010; das weiß ich nicht mehr so genau.RazorX hat geschrieben:ist aber auch erst seit Visual Studio 2013 der Fall. Vorher konnte man zwar auch die Kommentare schreiben und per Compiler in eine XML-Datei backen, aber IntelliSense hat den gesamten Inhalt unformatiert wiedergegeben.