Хабр Курсы для всех
РЕКЛАМА
Большая витрина: от крупнейших школ до частных авторов. Сравнивайте по цене, длительности, формату и выбирайте самый подходящий курс!
for(int i=0; i<n; i++){}// ясно
node *temp = NULL// вот тут явно NULL яснее смотрится чем 0?
#define NULL 0
f(int x);
void g() {
f(NULL);
}
Foo *a = new Foo();
// код код
if(a == 0)
void f(int x);
void g() {
int *p = 0;
f(p); // compile error
}
$ cat zz.cc
#include <iostream>
#include <stddef.h>
void f(int *x) { std::cout << "int *x" << std::endl; }
void f(int x) { std::cout << "int x" << std::endl; }
int main() {
f(0);
}
void f(int *x);
void g() {
f(2 * 21 - 42); // OK
}
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Product{
private:
int num;
// string name;
// string supplier;
// int count;
// string date;
public:
void input(){
// cout<<"Product: "; getline(cin, name);
// cout<<"Supplier: "; getline(cin, supplier);
// cout<<"Date: "; getline(cin, date);
// cout<<"Amount: "; cin>>count;
cout<<"Number of delivery: "; cin>>num;
}
static Product getkey(){
Product key;
cout<<"Key: ";
cin>>key.num;
return key;
}
void print(){
cout<<"Number of delivery: "<<num<<"\n";
// cout<<"Product: "<<name<<"\n";
// cout<<"Supplier: "<<supplier<<"\n";
// cout<<"Amount: "<<count<<"\n";
// cout<<"Date: "<<date<<"\n";
}
void output(ostream &stream){
stream<<num;
}
friend bool operator <(Product const a, Product const b){
return a.num < b.num;
}
friend bool operator ==(Product const a, Product const b){
return a.num == b.num;
}
};
class node
{
public:
Product data;
node *left,
*right;
void output(ostream &stream){
if(this != NULL){
left->output(stream);
data.output(stream);
stream<<" ";
right->output(stream);
}
}
node(Product var){
data = var;
left = right = NULL;
}
void remove(){
if(this != NULL){
left->remove();
right->remove();
delete left;
delete right;
}
}
~node(){
this->remove();
}
void output_sheets(){
if(this != NULL){
if(left == NULL && right == NULL){
data.print();
}else{
left->output_sheets();
right->output_sheets();
}
}
}
};
class bintree
{
private:
node *root;
public:
bintree(){
root = NULL;
}
bool add(){
Product new_data;
new_data.input();
if(root == NULL){
root = new node(new_data);
return true;
}
node *elem = root,
*parent = NULL;
bool isLeft;
while(elem != NULL){
if(new_data == elem->data){
return false;
}
isLeft = new_data < elem->data;
parent = elem;
if(isLeft){// если новый элемент меньше корня
elem = elem->left;
}else{
elem = elem->right;
}
}
if(isLeft){
parent->left = new node(new_data);
}else{
parent->right = new node(new_data);
}
return true;
}
void output(ostream &stream){
root->output(stream);
}
void remove_max(){
node *elem = root,
*prev = NULL;
while(elem->right != NULL){
prev = elem;
elem = elem->right;
}
if(elem == root){
root = root->left;
}else{
prev->right = NULL;
}
delete elem;
}
void output_sheets(){
root->output_sheets();
}
Product find(){
Product key = Product::getkey();
node *elem = root;
while(elem != NULL){
if(key == elem->data){
return elem->data;
}else if(key < elem->data){// если новый элемент меньше корня
elem = elem->left;
}else{
elem = elem->right;
}
}
return Product();
}
};
void clear(){
cout<<"\n";
for(int i=0; i<30; i++) cout<<"-";
cout<<"\n";
}
void menu(){
clear();
cout<<"1) Add node\n";
cout<<"2) Find node by key\n";
cout<<"3) Output tree\n";
cout<<"4) Remove node with max key\n";
cout<<"5) Output tree's sheets\n";
cout<<"6) Output in file\n";
cout<<"0) Quit\n";
cout<<"Your choise: ";
}
int main()
{
bintree tree;
int ch;
while(true)
{
menu();
cin>>ch;
switch(ch)
{
case 1:
if(!tree.add()){
cout<<"Element with this key exsist";
}else{
cout<<"Element succesfully added";
}
break;
case 2:
tree.find().print();
break;
case 3:
tree.output(cout);
break;
case 4:
tree.remove_max();
break;
case 5:
tree.output_sheets();
break;
case 6:{
char filename[50];
cout<<"Filename: ";
cin>>filename;
ofstream filestr(filename);
if (filestr.is_open()){
tree.output(filestr);
filestr.close();
}else{
cout << "Error opening file";
}
}
break;
case 0:
return 0;
break;
}
}
}
node *temp = root,
*prev = 0;
while(temp!=0){
prev = temp;
temp = temp->next;
}
prev->next = new node();
SomeClass *lv_Obj = 0;
lv_Obj->DoSmth(); // функция вызовется и если внутри нет обращения к полям то ещё и успешно выполнится.
while (1) { // НЕТ!
:
}
Так почему же зная то, что NULL = 0 — стоит писать 0
а в циклах такая запись не естественна?
Нельзя делать #define NULL whatever в пользовательском коде.
Нельзя переопределять имена из стандартной библиотеки. Почитайте что такое UB, узнаете много нового.
Нельзя делать #define NULL whatever в пользовательском коде.Можно, другое дело что это очень плохо, но тем не менее сделать это можно.
define, вы нарушили правила игры. Теперь ваша программа — уже не валидная программа на языке С++. Если это не указано явно, C++ считает, что возвращаемое значение имеет тип int.
51. Символ указателя или ссылки в языке C++ следует ставить сразу после имени типа, а не с именем переменной.
int* ptr, not_ptr;
int *ptr, not_ptr;
Stream *Stream1, *Stream2, *Stream3;
void setStream(Stream *Stream1, Stream *Stream2, Stream *Stream3);
s += L'\u2212' // 2212 = minus sign
dynamic_cast<TButton*>(Sender)->Tag, это не требуется, однако само событие должно иметь говорящее имя.const char* Printf::c_str(), но не cStr()EPreprocess = PreprocessException, nUsers = UserCount.carId — идентификационный код, отличающий машину от других, carIndex/iCar — номер машины из n шт., carCount/nCars — кол-во машин в гонке, carQty — кол-во машин в продаже, carNo — номер машины (государственный или стартовый).template<
class K,
class T,
class H,
class E,
class A
> class unordered_map;
template<
class Key,
class T,
class Hash,
class KeyEqual,
class Allocator
> class unordered_map;
И еще, я не могу
понять почему выравнивание улучшает читаемость
for (int tableNo = 0; tableNo < nTables;
tableNo += tableStep) {
...
}animState->setTimePosition(std::min(anim->getLength(), animState->getTimePosition())); animState->setTimePosition(
std::min(
anim->getLength(),
animState->getTimePosition()
)
);
deltaTransform.translate = srcBone->getInitialPosition() - dstBone->getInitialPosition();
deltaTransform.rotate = dstBone->getInitialOrientation().Inverse() * srcBone->getInitialOrientation();
deltaTransform.scale = srcBone->getInitialScale() / dstBone->getInitialScale();var tratata = MumbleThis(i, j);
var tratata = MumbleThis(year, dayOfYear);
a[month-1] = 0; Сиди и гадай потом, то ли это преобразование в индекс, то ли какая-то логика про предшествующий месяц. Все определения должны находиться в файлах исходного кода.
class MyClass { public: int getValue () {return value_;} // НЕЛЬЗЯ!
Без инлайнинга код начинает тормозить везде равномерно.
Кроме того, мы же обсуждаем «правило» что инлайн функции в классах определять «НЕЛЬЗЯ»
1. Допускаются любые нарушения рекомендаций, если это улучшает читаемость.
2. Правила могут быть нарушены, если против них есть персональные возражения.
Позволяет легко отличать переменные от типов, предотвращает потенциальные коллизии имён, например: Line line;
m_Field = lv_Field + _Offset;
/*
сразу при чтении понятно m_Field - поле класса lv_Field1 - локальная переменная метода _Offset - параметр метода.
при этом нет никаких конфликтов имён, быстро читается + при вводе m_ интелесенс сразу выведет поля также и при lv_ и _
/**/
field = field1 + offset; // что от чего и где совсем непонятно.
6. Названия методов и функций должны быть глаголами, быть записанными в смешанном регистре и начинаться с нижнего.
SomeObj.Method() // гармония
SomeObj.method() // дизгармония
7. Названия пространств имён следует записывать в нижнем регистре.
SomeNamespace::SomeObj.Method() // гармония
some_namespace::SomeObj.method() // дизгармония
8. Следует называть имена типов в шаблонах одной заглавной буквой.9. Аббревиатуры и сокращения в именах должны записываться в нижнем регистре.
11. Членам класса с модификатором private следует присваивать суффикс-подчёркивание.
12. Настраиваемым переменным следует давать то же имя, что и у их типа.
SomeFunc(string& stringPath, int CountInt, float OffsetFoloat) 14. Переменные, имеющие большую область видимости, следует называть длинными именами, имеющие небольшую область видимости — короткими.
17. Слова get/set должны быть использованы везде, где осуществляется прямой доступ к атрибуту.
18. Слово compute может быть использовано в методах, вычисляющих что-либо.
Дайте читающему сразу понять, что это времязатратная операция.
19. Слово find может быть использовано в методах, осуществляющих какой-либо поиск.
Следует избегать сокращения init.
21. Переменным, представляющим GUI, следует давать суффикс, соответствующий имени типа компонента.
23. Префикс n следует использовать для представления числа объектов.
28. Следует избегать сокращений в именах.
37. Содержимое файлов не должно превышать 80 колонок.
38. Нельзя использовать специальные символы (например, TAB) и разрывы страниц.
Такие символы вызывают ряд проблем, связанных с редакторами, эмуляторами терминалов и отладчиками, используемыми в программах для совместной разработки и кроссплатформенных средах.
40. Заголовочные файлы должны содержать защиту от вложенного включения.
51. Символ указателя или ссылки в языке C++ следует ставить сразу после имени типа, а не с именем переменной.
53. Следует избегать неявного сравнения булевых (логических) переменных и указателей с нулём.
if (nLines != 0) // в С++ это равносильно if (nLines != false)
58. Следует избегать использования break и continue в циклах.
Такие выражения следует использовать только тогда, когда они повышают читаемость.
Если это не указано явно, C++ считает, что возвращаемое значение имеет тип int.
71. Основной отступ следует делать в два пробела.
72. Блоки кода следует оформлять так, как показано в примере 1 (рекомендуется) или в примере 2, но ни в коем случае не так, как показано в примере 3. Оформление функций и классов должно следовать примеру 2.
89. Используйте выравнивание везде, где это улучшает читаемость.
if (a == lowValue) compueSomething();
else if (a == mediumValue) computeSomethingElse();
else if (a == highValue) computeSomethingElseYet();
и потом, допустим, должно быть SomeClass::Method(), но при этом someClass.method(); же, что еще больше путаницы создает.
Foo::Foo( int arg1, int arg2 )
: mArg1( arg1 )
, mArg2( arg2 )
{}class UniCorn {
public:
int get_x() {return X; };
void setX(int salad) { X = salad; };
int Y()
{
return _y;
}
void SetY(int JesusWillBeatTRex) {
_y = JesusWillBeatTRex;
}
private:
int X;
int _y;
};
mainWindow, propertiesDialog, widthScale, loginText, leftScrollbar, mainForm, fileMenu, minLabel, exitButton, yesToggle и т. д.
wndMain, dlgProperties, txtLogin, scrlLeft, frmMain, mnuFile, lblMin, btnExit и т. д.
while (true)
{
sendPacket("test");
checkInput();
}
int y = 0;
{
int x = 0;
...
}
int zzz;
{
Lock l(cs);
...
}
void
some_function()
{
do_some_stuff();
}
if/else).CamelCase;#pragma once;case, private, protected, public приравниваются к меткам;auto и decltype;static_assert;const в параметрах методов;final, override;constexpr;обычно находится пяток тем для споровне удивительно:
строчное написание везде, кроме имен типов, там — CamelCase
явное указание всех исключений, которые может выбросить метод
там, где можно — циклы по коллекции, вместо итераторов
_.__.___.throw не забываешь об исключениях, когда используешь метод.for(auto item : vect) {
/* do some stuff */
}
std::for_each(vect.begin(), vect.end(), [] (some_type item) -> void {
/* do some stuff */
});
struct some_functor {
void operator() (some_type item) {
/* do some stuff */
}
} my_functor;
/* ... */
std::for_each(vect.begin(), vect.end(), my_functor);
_.__.___
for(auto item : vect)std::for_each(v.begin(), v.end(), std::mem_fun(&cls::func));. Хотя, конечно, добавить ещё что-то будет сложнее.Благодаря throw не забываешь об исключениях, когда используешь метод
try {} catch (...) { throw my_exception(); }), но параною развивает. Дело ваше.As expressed in the national body comment above, exception specifications have not proven useful in practice. [...]
Underscores and lowercase was the style perferred by Bjarne Stroustrup in «The C++ Programming Language».
Особенно смешно совместно с рекомендацией использовать функции вместо констант.
Сей господин отдаёт себе отчёт, что это приведёт к явному вызову функции при практически каждом использовании константы?
constexpr int someIntConstant() { return 25; }
insert/delete
Prefer preincrement to postincrement whenever possible. Preincrement is potentially faster than postincrement. Just think about the obvious implementations of pre/post-increment. This rule applies to decrement too:
T old( *this ); // запомнить начальное значение
++*this; //инкрементировать
return old; //вернуть старое значение
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<string> vec (1000);
typedef vector<string>::const_iterator vi;
for ( vi i = vec.begin() ; i != vec.end(); i++) //соответственно во втором файле меняем на преинкремент
{
const string& str = *i;
string tmp = str;
}
return 0;
}


Use prefix form (++i) of the increment and decrement operators with iterators and other template objects.
string s1 = 'a';
s1 = s1 + 'b'; //способ 1
s1 += 'b'; //способ 2
Оба способа добавления к концу строки семантически эквивалентны, но я предпочитаю второй, потому что он более точно отражает смысл операции и, скорее всего, реализован более эффективно.
90 рекомендаций по стилю написания программ на C++