[C++] Snippets

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

[C++] Snippets

Beitrag von CodingCat »

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.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Re: [C++] Snippets

Beitrag von RazorX »

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);
            ...
        }
        ...
    }
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Snippets

Beitrag von CodingCat »

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:

Code: Alles auswählen

private:
   LockSection(const LockSection &); // Müssen nicht implementiert werden, da niemals aufgerufen
   LockSection& operator =(const LockSection &);
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).
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Schrompf »

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:

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
}
Das ist jetzt frei zusammengetippt, ich weiß ehrlich gesagt nicht, ob das so funktionieren würde. Aber es war eine spontane Idee.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Snippets

Beitrag von CodingCat »

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.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Andre
Establishment
Beiträge: 186
Registriert: 21.12.2011, 20:33

Re: [C++] Snippets

Beitrag von Andre »

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.
Sowas gibt es übrigens in der BOOST-Library fest eingebaut. Nennt sich scoped_mutex. Nur falls die jemand eh schon benutzt :)
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Snippets

Beitrag von kimmi »

Tu ich und das hat sich ausgezahlt :). Danke für die Snippets, da kann man sich noch was abschauen.

Gruß Kimmi
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Re: [C++] Snippets

Beitrag von RazorX »

Andre hat geschrieben:
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.
Sowas gibt es übrigens in der BOOST-Library fest eingebaut. Nennt sich scoped_mutex. Nur falls die jemand eh schon benutzt :)
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.
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Re: [C++] Snippets

Beitrag von RazorX »

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.

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

// ...
};
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.
Benutzeravatar
dot
Establishment
Beiträge: 1745
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] Snippets

Beitrag von dot »

Ist das denn so überhaupt erlaubt? COM kennt afaik nur Interfaces und ein Objekt kann verschiedene Interfaces implementieren, aber keine Ableitungsbeziehungen...
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Re: [C++] Snippets

Beitrag von RazorX »

Zumindest in der MSDN steht auch immer brav geschrieben von welchen COM Interfaces die einzelnen Interfaces erben.
Beispiel: ID3D11Texture2D -> ID3D11Resource -> ID3D11DeviceChild -> IUnknown
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Krishty »

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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Krishty »

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.

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
Bzw. die double-Versionen:

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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Krishty »

Eine Datei unter Windows in den Speicher mappen:

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();
}
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:

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;
};
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");
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Snippets

Beitrag von CodingCat »

arraylen-Update für statisch referenzierte Members:

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)))
Ermöglicht:

Code: Alles auswählen

struct foo { int bar[5]; };
arraylen(foo::bar)
Irgendwelche Einwände bezüglich &(a) im Makro?
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: [C++] Snippets

Beitrag von eXile »

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;
}
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Krishty »

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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Snippets

Beitrag von CodingCat »

Zwei verallgemeinernde Schleifenmuster, die mir elegant erscheinen:

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);
   // ...
}
Man beachte, dass keine Negationen oder Vergleiche eingefügt werden. Beide Muster sollten in den meisten (allen?) Fällen optimalen Code generieren.
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
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: [C++] Snippets

Beitrag von kimmi »

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
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] Snippets

Beitrag von CodingCat »

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.
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.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [C++] Snippets

Beitrag von BeRsErKeR »

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))
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:

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
Mit diesen Erweiterungen kann man Compiler-Warnungen und -Fehler simulieren. Die Syntax ist identisch zu der von Warnungen und Fehlern, die der Compiler generiert. Das Schmankerl an der Sache ist, dass der Aufruf von COMPILER_ERROR tatsächlich dafür sorgt, dass die Kompilierung fehlschlägt. Im Gegensatz zu #error bricht es aber nicht beim Aufruf die Kompilierung ab, was ein großer Vorteil sein kann. Die erzeugten Warnungen und Fehler werden auch anders eingerückt als normale Nachrichten.

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.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Krishty »

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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: [C++] Snippets

Beitrag von BeRsErKeR »

Krishty hat geschrieben:Vielleicht kann, wer auf diesen Systemen entwickelt, was damit anfangen.
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.
Ohne Input kein Output.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4273
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: [C++] Snippets

Beitrag von Chromanoid »

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.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Krishty »

  // 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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Re: [C++] Snippets

Beitrag von RazorX »

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);
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4273
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: [C++] Snippets

Beitrag von Chromanoid »

@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
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Krishty »

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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
RazorX
Establishment
Beiträge: 156
Registriert: 23.12.2010, 14:13
Kontaktdaten:

Re: [C++] Snippets

Beitrag von RazorX »

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.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] Snippets

Beitrag von Krishty »

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.
vs2012 comment format.png
vs2012 comment format.png (8.27 KiB) 6624 mal betrachtet
2012 :-) Unter Umständen war es auch schon in Visual Studio 2010; das weiß ich nicht mehr so genau.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten