std::auto_ptr
является устаревшим и удален из стандартной библиотеки начиная со стандарта C++17.std::unique_ptr
.std::auto_ptr
мог следить только за памятью одного экземпляра. Передать туда память массива можно, но деструктор будет вызван только у первого экземпляра массива. В общем смысле это означает утечку памяти.std::unique_ptr
, наоборот, способен контролировать память как единичного экземпляра, так и массива экземпляров. Еще в отличии от своего устаревшего товарища, std::unique_ptr
способен спокойно передавать свое состояние, не создавая возможность двойного освобождения памяти. В дополнение, std::unique_ptr
еще способен пользоваться нестандартными деструкторами, что очень кстати при работе, например, с COM-объектами или нестандартной схемой аллокации памяти.main
.void swap(T& first, T& second)
.std::swap
.template <typename T1>
void out_array(const T1* array, size_t arraySize)
arraySize
тоже не нужен. Ты работаешь с сырыми массивами фиксированной длины и можешь дать своему шаблону функции понимание длины такого массива. Делается это так.template < typename TElementType, size_t LENGTH >
void out_array( const TElementType array[ LENGTH ] )
char array2[n] = { '2','1','4','5','3','-3','-1','-2','-4','-5' };
'2'
не будет эквивалентно 2
. С этого момента сортировка будет сортировать по коду символьной таблицы, а не по значению числа. Это ошибка, т.к. это явно не то поведение, которое ты ждешь.'-3'
и.т.д. Тип у такой конструкции будет int
, а не char
. Компилятор тебе именно об этом и пытается сказать.int array3[n] = atoi(array2);
int array3[n];
std::transform(
std::begin( array2 ), std::end( array2 ), std::begin( array3 ),
[]( const char item ) -> int { return item; }
);
std::transform
. Node root = {T{}, nullptr, nullptr};
Node root{T{}, nullptr, nullptr};
template <typename T>
struct NameOf {};
NameOf
. Определение это я сразу назову неправильным, потому что от этого шаблона можно инстанцировать тип и получить совершенно непонятную ошибку компиляции дальше. Должно быть так, чтобы тип из общей формы шаблона инстанцировать было нельзя.#define DEF_TYPENAME(type) template <> \
struct NameOf<type> {\
static const char value[];\
};\
const char NameOf<type>::value[] = #type;
NameOf
для переданного типа. Тут я скажу только то, что можно сделать полностью иначе и макрос тут полностью не нужен.DEF_TYPENAME(int)
DEF_TYPENAME(double)
DEF_TYPENAME(long double)
DEF_TYPENAME(float)
DEF_TYPENAME(char)
DEF_TYPENAME(long)
DEF_TYPENAME(unsigned)
DEF_TYPENAME(unsigned long)
;
все таки был бы более уместен в этом месте, т.к. сейчас код выглядит несвязной простыней без структуры. Сразу хочется сказать что тут синтаксическая ошибка, хоть на самом деле это и не так.NameOf
.template <typename T, typename ...types>
void printTypes(T)
{
std::cout << NameOf<T>::value << std::endl;
}
template <typename T, typename ...types>
void printTypes(T, types... t)
{
std::cout << NameOf<T>::value << ", ";
printTypes(t...);
}
printTypes
из шаблона. Я сейчас остановлюсь лишь на второй ветви вывода.template <typename T, typename ...types>
void printTypes(T, types... t)
{
std::cout << NameOf<T>::value << ", ";
printTypes(t...);
}
typename ...types
в объявлении шаблона говорит что типов ожидается от нуля и пока фантазия не кончится. Как пользоваться таким шаблонами - хорошо описано в документации по моей ссылке.std::cout << NameOf<T>::value << std::endl;
. ::new
является точкой обращения к аллокатору памяти процесса. К какому именно аллокатору идет обращение - как правило неизвестно. Это может быть dlmalloc
, mimalloc
или jemalloc
. Их много и перечислять можно долго. Это может быть и самостоятельно созданный по мотивам доклада Александреску аллокатор.::delete
). IMagicSpell::ShowDebugInfo
у тебя обращается к приватному полю IMagicSpell::SpellInfo
. Это поле недоступно для наследников, т.к. является приватным.Fireball::Fireball
, у тебя работает с приватным полем Fireball::SpellInfo
.IMagicSpell::SpellInfo
и Fireball::SpellInfo
являются разными, расположены в разных областях памяти объекта Fireball
и в принципе никак не могут пересечься своими данными.Fireball
будет с два MagicSpellInfo
плюс размер таблицы виртуальных символов.MagicSpellInfo
в иерархии - лишний. Fireball::SpellInfo
является дублирующим, лишним полем, которое не позволяет добиться необходимой тебе функциональности. Ведь в обоих твоих классах тебе надо работать с одними данными, с полем IMagicSpell::SpellInfo
.Fireball::SpellInfo
.class Fireball: public IMagicSpell {
public:
Fireball() {
SpellInfo.Name = "Огненный шар";
SpellInfo.Description = "Мощный огненный шар, сметающий все на своем пути.";
SpellInfo.Type = fire;
SpellInfo.MinDamage = 30;
SpellInfo.MaxDamage = 50;
SpellInfo.Range = 40;
SpellInfo.Distance = 120;
}
virtual ~Fireball() {}
virtual void Use() {
cout << "Boom!" << endl;
}
};
IMagicSpell::SpellInfo
является приватным и недоступен для потомков. Исправить это тоже очень легко. private
- приватный доступ, только для экземпляра текущего класса;protected
- ограниченный доступ, только для экземпляров текущего класса и всех публичных наследников; доступ ограничивается при ограниченном или приватном наследовании;public
- публичный доступ, для всех пользователей экземпляров класса.IMagicSpell::SpellInfo
с приватного на ограниченный. В этом случае экземпляры Fireball
смогут обращаться к IMagicSpell::SpellInfo
как к своему ограниченному полю.class IMagicSpell {
protected:
MagicSpellInfo SpellInfo;
public:
virtual ~IMagicSpell() {}
virtual void Use() {}
MagicSpellInfo GetInfo() {
return this->SpellInfo;
}
void ShowDebugInfo() {
cout << "Название: " << SpellInfo.Name << endl;
cout << "Описание: " << SpellInfo.Description << endl;
cout << "Тип: " << SpellInfo.Type << endl;
cout << "Мин. урон: " << SpellInfo.MinDamage << endl;
cout << "Макс. урон: " << SpellInfo.MaxDamage << endl;
cout << "Расстояние: " << SpellInfo.Distance << endl;
cout << "Радиус: " << SpellInfo.Range << endl;
}
};
get_substr("один", "два три четыре")
, ты в функцию передаешь два строковых литерала, тип которых - const char[ N ]
, где N
- это длина строки литерала включая терминальный символ '\0'
.const char*
в char*
недопустимо, поэтому компилятор и пишет тебе ошибку.char*
вообще не нужен, т.к. полностью все операции у тебя не приводят к изменению состояния строки. Заменить char*
на const char*
будет и логичнее, и понимаемость кода тоже улучшит. debug
и принимает аргумент, но вне отладочной конфигурации он этим аргументом не оперирует. В любом месте обращения к твоему макросу произойдет подстановка NULL
вместо всего обращения.NULL
в качестве подстановки не нужен. Зачем тебе в коде программы обилие висящих NULL
? Если описать макрос так:#ifdef DEBUG
#define debug(n) Serial.println("***"+String(n)+"***")
#else
#define debug(n)
#endif
operator<<(ofstream&, const Book&)
должен быть определен в пространстве имен std
, т.к. ofstream
определен именно в этом пространстве.namespace std
{
// use the `Book` type definitely from global namespace.
ofstream& operator<<(ofstream &of, const ::Book &book)
{
// ...
}
}
И еще вопрос: что нужно возвращать из этой функции?
glutPostRedisplay
.double GetCurrentTime()
{
using Duration = std::chrono::duration<double>;
return std::chrono::duration_cast<Duration>(
std::chrono::high_resolution_clock::now().time_since_epoch()
).count();
}
const double frame_delay = 1.0 / 60.0; // 60 FPS
double last_render = 0;
void OnIdle()
{
const double current_time = GetCurrentTime();
if( ( current_time - last_render ) > frame_delay )
{
last_render = current_time;
glutPostRedisplay();
}
}
double
помогает легче находить дельту между кадрами и контролировать ошибку дельты.5
будет являться числовым литералом с типом int
.5u
, то тип бы уже был unsigned int
. А если бы ты написал 5lu
, то тип бы уже был unsigned long int
. glutIdleFunc
. В документации написано что GLUT будет постоянно вызывать переданную функцию в свободное от обработки системных сообщений время. А если в glutIdleFunc
передан nullptr
(или idle-функция не была задана), то GLUT будет строго ждать следующего системного сообщения.glutPostRedisplay
, в glutIdleFunc
приведет и к регулярной перерисовке экрана.operator()
.int N = 0;
bool GreatherThanN(int x) {
if (x > N) {
return true;
}
return false;
}
template< int N >
bool GreatherThanN(int x) {
if (x > N) {
return true;
}
return false;
}
N
в этом случае надо знать на этапе компиляции. Да и в целом, не всё можно определить через параметры шаблона. Параметром шаблона может быть или тип, или константа целочисленного типа или типа сводимого к целочисленному (enum, bool, const char*, известные на этапе компиляции указатели).operator()
.struct Comparator final
{
int N;
inline const bool operator () ( int x ) const
{
return x > N;
}
};
// ...
Comparator GreatherThanN{ 10 };
// ...
count_if(begin(v), end(v), GreatherThanN);
#include <iostream>
using namespace std;
const char ssid[] = "TEST";
const char password[] = "123456";
struct Wifi {
const char *access[2][2];
} wifi{
{
{ ssid, password },
{ "DIR", "654321" }
}
};
int main() {
for (int i = 0; i < sizeof(wifi.access) / sizeof(wifi.access[0]); i++) {
cout << wifi.access[i][0] << ": " << wifi.access[i][1] << '\n';
// TEST: 123456
// DIR: 654321
}
return 0;
}