Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
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_;} // НЕЛЬЗЯ!
Без инлайнинга код начинает тормозить везде равномерно.
Кроме того, мы же обсуждаем «правило» что инлайн функции в классах определять «НЕЛЬЗЯ»
m_name;
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++