class Mutex {
public:
void enter();
void leave();
}
class Lock {
public:
Lock(Mutex& aMutex) : mutex(aMutex) { mutex.enter(); }
~Lock() { mutex.leave(); }
private:
Mutex& mutex;
}
…
Mutex mutex;
{ Lock lock(mutex);
// всё, что здесь, выполняется внутри мьютекса.
// Даже если выпадет авария, из мьютекса корректно выйдем.
}
char * a = "hello!";
3) Использование инициализации списком для структур (POD) с уже прединициализированными полями:
1) Разное содержимое одних и тех же хедеров
2) MSVC спокойно компилирует нечто вроде
но при этом не компилирует код, если не-void функция не возвращает значение
Foo foo;
if (someFlag)
foo.init("SomeString");
else foo.init(42);
class FooWrap {
public:
FooWrap() : hasFoo(false) {}
void init(int x) { new (fooPlace) Foo(x); hasFoo = true; }
Foo& operator * () { return *reinterpret_cast<Foo*>(fooPlace); }
Foo* operator -> () { return reinterpret_cast<Foo*>(fooPlace); }
~FooWrap() { if (hasFoo) (*this)->~Foo(); }
// Да, и конструктор копирования и op= не забыть — оставлю как упражнение.
private:
char fooPlace[sizeof(Foo)];
bool hasFoo;
}
FooWrap foo;
if (someFlag)
foo.init("SomeString");
else foo.init(42);
foo->doFoo();
// Не компилируется!
class A;
namespace XXX {
std::shared_ptr<A> a;
class A { public: int x; };
void xxx();
}
void XXX::xxx() {
a->x;
}
// Компилируется!
class A;
namespace XXX {
class A { public: int x; };
std::shared_ptr<A> a;
void xxx();
}
void XXX::xxx() {
a->x;
}
// Тоже компилируется!
namespace XXX {
class A;
}
namespace XXX {
std::shared_ptr<A> a;
class A { public: int x; };
void xxx();
}
void XXX::xxx() {
a->x;
}
shared_ptr<::A>
, который, естественно, не определён (есть XXX::A
).shared_ptr<XXX::A>
.std::vector<char>
. Что вместо SetLength — читай доку.struct Row {
int data[10];
};
struct Table {
Row rows[10];
}
int sortJ;
int myCompare(const void* a,const void* b) {
int ia = reinterpret_cast<Row*>(a)->data[sortJ];
int ib = reinterpret_cast<Row*>(b)->data[sortJ];
if (ia < ib) return -1;
if (ia == ib) return 0;
return 1;
}
int someJ = 5;
sortJ = someJ;
qsort(table.rows, 10, sizeof(Row), myCompare);
class MyCompare {
public:
MyCompare(int aJ) : j(aJ) {}
bool operator () (const Row& a, const Row& b) const
{ return (a.data[j] < b.data[j]); }
private:
const int j;
}
int someJ = 5;
std::sort(table.rows, table.rows + 10, MyCompare(someJ));
int someJ = 5;
std::sort(table.rows, table.rows + 10,
[someJ](const Row& a, const Row& b) -> bool { return (a.data[someJ] < b.data[someJ]); } );
connect(this, &RenewThread::needUpdate, fMainControl.maincQobj(),
[this]() {
drm::createFile(fReregKey);
fMainControl.maincLayoutOnRegister();
});
HRESULT EnumObjects(
LPDIENUMDEVICEOBJECTSCALLBACK lpCallback,
LPVOID pvRef,
DWORD dwFlags
);
BOOL DIEnumDeviceObjectsCallback(
LPCDIDEVICEOBJECTINSTANCE lpddoi,
LPVOID pvRef
);
template<>
).struct CheckLine {
public:
int itemCode; // код товара
int qty; // количество
int price; // цена, по которой всё это продано в копейках
const CheckLine* next() const { return _next; }
private:
friend class Check; // я тут ошибся с const-корректностью и заconst’ив всё, что можно, не дал Check’у писать
CheckLine* _next;
}
class Check {
public:
Check() : _firstLine(NULL), _lastLine(NULL) {}
void addLine(int itemCode, int qty, int price); // пиши реализацию сам.
const CheckLine* firstLine() const { return _firstLine; }
~Check(); // не забудь про деструктор…
Check(const Check&) // …конструктор копирования…
Check& operator = (const Check&); // и операцию «присвоить».
private:
CheckLine *_firstLine, *_lastLine;
}
///// Защита от повторного включения
#ifndef Unit1H
#define Unit1H
///// Хедеры VCL. Причём всё это сделано так, чтобы упростить написание ценой удлинения
///// компиляции. Более громоздкий, но и более удачный вариант.
///// В H:
///// namespace Controls { class TLabel; }
///// using namespace Controls;
///// В CPP:
///// #include <Controls.hpp>
///// Вот таким образом можно (было) избавиться от каскадного подключения
///// хедера Controls. А то каждый, кто использует главной форму,
///// автоматически подключает эти хедеры.
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
///// Только от Forms.hpp избавиться таким макаром нельзя:
///// мы наследуемся от TForm.
#include <Forms.hpp>
///// Класс формы. Все формы наследуются от TForm.
class TForm1 : public TForm
{
///// Особое право доступа Borland, для совместимости с Delphi.
///// Поля и свойства published не просто public, но включаются
///// в структуру рефлексии (aka reflection или introspection)
///// и программа о них знает при выполнении.
///// Применительно к формам — published-поля доступны
///// загрузчику.
__published: // IDE-managed Components
///// Компоненты, которые мы установили на форме редактором.
TLabel *Label1;
TButton *Button1;
///// События, которые мы прописали в редакторе.
///// __fastcall — модель вызова, аналогичная Delphi.
///// Именно такая модель вызова принята в обработчиках
///// событий.
void __fastcall Button1Click(TObject *Sender);
///// Пользователь пока не прописал никаких своих
///// полей и функций.
private: // User declarations
public: // User declarations
///// Конструктор. Раз уж у формы нетривиальный конструктор —
///// по правилам Си++ его надо повторить в подклассе.
///// Снова-таки, модель вызова __fastcall: в формах Delphi
///// используются т.н. виртуальные конструкторы,
///// когда по имени класса можно создать объект этого класса.
///// Фабричный метод, только немного лучше.
///// Но это значит: у всех подчинённых классов
///// должен быть один и тот же набор параметров
///// и модель вызова.
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
///// Как известно, переменная объявляется один раз.
///// Поскольку хедер может подключаться к огромному числу CPP,
///// её объявляют как extern (она есть, но в другом месте).
///// Макрос PACKAGE раскрывается в __declspec(package),
///// чтобы эту штуку можно было собрать как пакет.
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif