diff options
-rw-r--r-- | ru-ru/c++-ru.html.markdown | 582 |
1 files changed, 289 insertions, 293 deletions
diff --git a/ru-ru/c++-ru.html.markdown b/ru-ru/c++-ru.html.markdown index 99798bbb..5137ec1f 100644 --- a/ru-ru/c++-ru.html.markdown +++ b/ru-ru/c++-ru.html.markdown @@ -162,7 +162,7 @@ void foo() int main() { - // Включает все функци с пространства имен Second в текущую область видиомти. + // Включает все функци с пространства имен Second в текущую область видимости. // Обратите внимание, что простой вызов foo() больше не работает, // так как теперь не ясно вызываем ли мы foo с пространства имен Second или // из глобальной области видимости. @@ -177,26 +177,26 @@ int main() // Ввод/Вывод /////////////// -// C++ input and output uses streams -// cin, cout, and cerr represent stdin, stdout, and stderr. -// << is the insertion operator and >> is the extraction operator. +// Вводи и вывод в C++ использует потоки +// cin, cout и cerr предоставлнеы методами stdin, stdout и stderr. +// << - оператор вставки, >> - оператор извлечения. -#include <iostream> // Include for I/O streams +#include <iostream> // Включение файла для работы с потоками Ввода\Вывода. -using namespace std; // Streams are in the std namespace (standard library) +using namespace std; // Потоки доступны в пространстве имен std (стандартная библиотека) int main() { int myInt; - // Prints to stdout (or terminal/screen) + // Выводит stdout (или терминал\экран) cout << "Enter your favorite number:\n"; - // Takes in input + // Принимает ввод cin >> myInt; - // cout can also be formatted + // cout может принимать форматирование cout << "Your favorite number is " << myInt << "\n"; - // prints "Your favorite number is <myInt>" + // напечатает "Your favorite number is <myInt>" cerr << "Used for error messages"; } @@ -205,35 +205,35 @@ int main() // Строки ////////// -// Strings in C++ are objects and have many member functions +// Строки в C++ являются объектами и имеют много функций-членов. #include <string> -using namespace std; // Strings are also in the namespace std (standard library) +using namespace std; // Строки также доступны в пространстве имен std (стандартная библиотек) string myString = "Hello"; string myOtherString = " World"; -// + is used for concatenation. +// + используется для конкатенации строк. cout << myString + myOtherString; // "Hello World" cout << myString + " You"; // "Hello You" -// C++ strings are mutable and have value semantics. +// Строки в C++ могут изменяться и имеют семантику значений. myString.append(" Dog"); cout << myString; // "Hello Dog" ///////////// -// References +// Ссылки ///////////// -// In addition to pointers like the ones in C, -// C++ has _references_. -// These are pointer types that cannot be reassigned once set -// and cannot be null. -// They also have the same syntax as the variable itself: -// No * is needed for dereferencing and -// & (address of) is not used for assignment. +// В добавок к указателям доступных в C, +// C++ имеет _ссылки_. +// Это такой тип указателя, который не может быть переназначен после инициализации +// и не может иметь значения null. +// Ссылки имеют схожий с переменными синтаксис: +// * больше не используется для разыменования и +// & (адрес) не используется для назначения. using namespace std; @@ -241,84 +241,80 @@ string foo = "I am foo"; string bar = "I am bar"; -string& fooRef = foo; // This creates a reference to foo. -fooRef += ". Hi!"; // Modifies foo through the reference -cout << fooRef; // Prints "I am foo. Hi!" +string& fooRef = foo; // Здесь создается указатель на foo. +fooRef += ". Hi!"; // Изменяет foo по ссылке +cout << fooRef; // Печатает "I am foo. Hi!" -// Doesn't reassign "fooRef". This is the same as "foo = bar", and +// Не переназначает "fooRef". Это тоже самое как "foo = bar", и // foo == "I am bar" -// after this line. -cout << &fooRef << endl; //Prints the address of foo +// после этой строчки. +cout << &fooRef << endl; // Печатает адрес foo fooRef = bar; -cout << &fooRef << endl; //Still prints the address of foo -cout << fooRef; // Prints "I am bar" +cout << &fooRef << endl; // По-прежнему печатает адрес foo +cout << fooRef; // Печатает "I am bar" -//The address of fooRef remains the same, i.e. it is still referring to foo. +// Адрес fooRef остается тем же, то есть он по-прежнему ссылается на foo. -const string& barRef = bar; // Create a const reference to bar. -// Like C, const values (and pointers and references) cannot be modified. -barRef += ". Hi!"; // Error, const references cannot be modified. +const string& barRef = bar; // Создает const со ссылкой на bar. +// Также как и C, значения const (и указателей и ссылок) не могут быть изменены. +barRef += ". Hi!"; // Ошибка, указатель const не может быть изменен. -// Sidetrack: Before we talk more about references, we must introduce a concept -// called a temporary object. Suppose we have the following code: +// Обходной путь: Прежде чем мы рассмотрим указатели более детально, нам нужно ознакомится +// с концепцией известной как "временный объект". Представьте, что мы имеем следующий код string tempObjectFun() { ... } string retVal = tempObjectFun(); -// What happens in the second line is actually: -// - a string object is returned from tempObjectFun -// - a new string is constructed with the returned object as argument to the -// constructor -// - the returned object is destroyed -// The returned object is called a temporary object. Temporary objects are -// created whenever a function returns an object, and they are destroyed at the -// end of the evaluation of the enclosing expression (Well, this is what the -// standard says, but compilers are allowed to change this behavior. Look up -// "return value optimization" if you're into this kind of details). So in this -// code: +// Вот что на самом деле происходит во второй строе: +// - tempObjectFun возвращает строковый объект +// - с возвращаемого объекта создается новая строка в качестве аргумента конструктору +// - возвращаемый объект уничтожается +// Возвращаемый объект называется временным объектом. Временные объекты создаются +// когда функция возвращает объект, и уничтожаются в конце выполнения обрамляющего +// выражения (По крайней мере, так это описывает спецификация, хотя компиляторы могут +// изменять это поведение. Для более подробной информации смотрите "оптимизация +// возвращаемого значения". Таким образом в этом коде: foo(bar(tempObjectFun())) -// assuming foo and bar exist, the object returned from tempObjectFun is -// passed to bar, and it is destroyed before foo is called. +// предполагая, что foo и bar существуют, объект возвращаемый tempObjectFun передается +// в bar, и уничтожается перед вызовом foo. -// Now back to references. The exception to the "at the end of the enclosing -// expression" rule is if a temporary object is bound to a const reference, in -// which case its life gets extended to the current scope: +// Возвращаемся к указателям. Исключением для правила "в конце выполнения обрамляющего +// выражения" является временный объект привязанный к ссылке const, в этом случае +// его жизненный цикл продлевается до текущей области видимости: void constReferenceTempObjectFun() { - // constRef gets the temporary object, and it is valid until the end of this - // function. + // constRef получает временный объект, и он действителен до конца этой функции. const string& constRef = tempObjectFun(); ... } -// Another kind of reference introduced in C++11 is specifically for temporary -// objects. You cannot have a variable of its type, but it takes precedence in -// overload resolution: +// В C++11 предоставлен еще один тип ссылок специально для временных объектов. +// objects. Вы не можете объявить переменную этого типа, но он имеет приоритет в +// в резолюции перегрузки: -void someFun(string& s) { ... } // Regular reference -void someFun(string&& s) { ... } // Reference to temporary object +void someFun(string& s) { ... } // Обычная ссылка +void someFun(string&& s) { ... } // Ссылка на временный объект string foo; -someFun(foo); // Calls the version with regular reference -someFun(tempObjectFun()); // Calls the version with temporary reference +someFun(foo); // Выполняет версию с обычной ссылкой +someFun(tempObjectFun()); // Выполняет версию с временной ссылкой. -// For example, you will see these two versions of constructors for -// std::basic_string: +// Например, существуют следующие две версии конструктора std::basic_string: basic_string(const basic_string& other); basic_string(basic_string&& other); -// Idea being if we are constructing a new string from a temporary object (which -// is going to be destroyed soon anyway), we can have a more efficient -// constructor that "salvages" parts of that temporary string. You will see this -// concept referred to as "move semantics". +// Идея в том, если мы конструируем новую строку из временного объекта (который +// так или иначе будет уничтожен), мы можем использовать более эффективный конструктор, +// который "спасает" части этой временной строки. Эта концепция была названа +// "move semantics". ///////////////////// -// Enums +// Перечисления ///////////////////// -// Enums are a way to assign a value to a constant most commonly used for -// easier visualization and reading of code +// Перечисления - способ объявления констант и установки их значений в основном +// использующийся для упрощения чтения кода. enum ECarTypes { Sedan, @@ -332,9 +328,9 @@ ECarTypes GetPreferredCarType() return ECarTypes::Hatchback; } -// As of C++11 there is an easy way to assign a type to the enum which can be -// useful in serialization of data and converting enums back-and-forth between -// the desired type and their respective constants +// На момент выхода C++11 есть простой способ назначения типа перечисления, что +// полезно в случае сериализации данных и преобразований между конечным типом и +// соответствующими константами. enum ECarTypes : uint8_t { Sedan, // 0 @@ -345,18 +341,19 @@ enum ECarTypes : uint8_t void WriteByteToFile(uint8_t InputValue) { - // Serialize the InputValue to a file + // Сериализуем InputValue в файл } void WritePreferredCarTypeToFile(ECarTypes InputCarType) { - // The enum is implicitly converted to a uint8_t due to its declared enum type + // Перечисление неявно преобразуется в uint8_t из-за раннее объявленного + // типа перечисления. WriteByteToFile(InputCarType); } -// On the other hand you may not want enums to be accidentally cast to an integer -// type or to other enums so it is instead possible to create an enum class which -// won't be implicitly converted +// С другой стороны, чтобы избежать случайного приведения к целочисленному типу или +// другому перечислению, вы можете создать класс перечисления, который не будет +// преобразовываться неявно. enum class ECarTypes : uint8_t { Sedan, // 0 @@ -367,78 +364,78 @@ enum class ECarTypes : uint8_t void WriteByteToFile(uint8_t InputValue) { - // Serialize the InputValue to a file + // Сериализуем InputValue в файл } void WritePreferredCarTypeToFile(ECarTypes InputCarType) { - // Won't compile even though ECarTypes is a uint8_t due to the enum - // being declared as an "enum class"! + // Хотя ECarTypes имеет тип uint8_t, код не будет скомпилирован из-за того, + // что перечисление было объявлено как класс перечисления. WriteByteToFile(InputCarType); } ////////////////////////////////////////// -// Classes and object-oriented programming +// Классы и объектно-ориентированное программирование ////////////////////////////////////////// -// First example of classes +// Пример классов #include <iostream> -// Declare a class. -// Classes are usually declared in header (.h or .hpp) files. +// Объявление класса. +// Обычно классы объявляют в заголовочном (.h или .hpp) файле. class Dog { - // Member variables and functions are private by default. + // Переменный-члены и функции являются частными по умолчанию. std::string name; int weight; -// All members following this are public -// until "private:" or "protected:" is found. +// Все члены после этой сроки являются открытыми +// пока "private:" или "protected:" не будет объявлено. public: - // Default constructor + // Конструктор по умолчанию Dog(); - // Member function declarations (implementations to follow) - // Note that we use std::string here instead of placing + // Объявление функций-членов + // Обратите внимание, мы используем std::string здесь вместо использования // using namespace std; - // above. - // Never put a "using namespace" statement in a header. + // выше. + // Никогда не размещайте выражение "using namespace" в заголовке. void setName(const std::string& dogsName); void setWeight(int dogsWeight); - // Functions that do not modify the state of the object - // should be marked as const. - // This allows you to call them if given a const reference to the object. - // Also note the functions must be explicitly declared as _virtual_ - // in order to be overridden in derived classes. - // Functions are not virtual by default for performance reasons. + // Функции, которые не изменяют состояние объекта, + // должны быть помечены как const. + // Это позволяет вызывать их если дана const ссылка на объект. + // Обратите внимание, функции должны быть явно объявлены как _virtual_ + // если вы хотите перегрузить их в производных классах. + // Функции не являются виртуальными по умолчания для повышения производительности. virtual void print() const; - // Functions can also be defined inside the class body. - // Functions defined as such are automatically inlined. + // Такде функции могут быть определены внутри тела класса. + // Функции, определенные следующим образом, автоматически встроены. void bark() const { std::cout << name << " barks!\n"; } - // Along with constructors, C++ provides destructors. - // These are called when an object is deleted or falls out of scope. - // This enables powerful paradigms such as RAII - // (see below) - // The destructor should be virtual if a class is to be derived from; - // if it is not virtual, then the derived class' destructor will - // not be called if the object is destroyed through a base-class reference + // Наряду с конструкторами, в C++ есть деструкторы. + // Они вызываются, когда объект удаляется или выпадает с области видимости. + // Это активирует мощную парадигму программирования известную как RAII + // (смотрите ниже) + // Деструктор должен быть виртуальным, если класс будет производным. + // Если он не виртуальный, тогда деструктор производного класса не будет вызван + // если объект удален по ссылке или указателю базового класса. // or pointer. virtual ~Dog(); -}; // A semicolon must follow the class definition. +}; // Определение класса должно завершатся точкой с запятой. -// Class member functions are usually implemented in .cpp files. +// Функции-члены класса, как правило, реализуются в .cpp файлах. Dog::Dog() { std::cout << "A dog has been constructed\n"; } -// Objects (such as strings) should be passed by reference -// if you are modifying them or const reference if you are not. +// Объекты (такие как строки) должны передаваться по ссылке если вы будете +// изменять их, или const-ссылке если нет. void Dog::setName(const std::string& dogsName) { name = dogsName; @@ -449,7 +446,7 @@ void Dog::setWeight(int dogsWeight) weight = dogsWeight; } -// Notice that "virtual" is only needed in the declaration, not the definition. +// Обратите внимание, "virtual" требуется только в объявлении, не в определении. void Dog::print() const { std::cout << "Dog is " << name << " and weighs " << weight << "kg\n"; @@ -461,35 +458,34 @@ Dog::~Dog() } int main() { - Dog myDog; // prints "A dog has been constructed" + Dog myDog; // Печатает "A dog has been constructed" myDog.setName("Barkley"); myDog.setWeight(10); - myDog.print(); // prints "Dog is Barkley and weighs 10 kg" + myDog.print(); // Печатает "Dog is Barkley and weighs 10 kg" return 0; -} // prints "Goodbye Barkley" +} // Печатает "Goodbye Barkley" -// Inheritance: +// Интерфейсы: -// This class inherits everything public and protected from the Dog class -// as well as private but may not directly access private members/methods -// without a public or protected method for doing so +// Этот класс наследует все открытые и защищенные члены класса Dog +// также как и все закрытые, но не может непосредственно получить доступ к закрытым +// членам\методам без открытых или защищенных методов для этого. class OwnedDog : public Dog { void setOwner(const std::string& dogsOwner); - // Override the behavior of the print function for all OwnedDogs. See - // http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping - // for a more general introduction if you are unfamiliar with - // subtype polymorphism. - // The override keyword is optional but makes sure you are actually - // overriding the method in a base class. + // Переопределяем поведение функции печати для всех OwnedDog. Смотрите + // https://goo.gl/3kuH2x для боле общего введения, если вы не знакомы + // с концепцией полиморфизма подтипов (включения). + // Ключевое слово override является необязательным, но указывает что метод + // на самом деле перегружается в базовом классе. void print() const override; private: std::string owner; }; -// Meanwhile, in the corresponding .cpp file: +// Тем временем, в соответствующем .cpp файле: void OwnedDog::setOwner(const std::string& dogsOwner) { @@ -498,53 +494,54 @@ void OwnedDog::setOwner(const std::string& dogsOwner) void OwnedDog::print() const { - Dog::print(); // Call the print function in the base Dog class + Dog::print(); // Вызывает функцию print в базовом классе Dog std::cout << "Dog is owned by " << owner << "\n"; - // Prints "Dog is <name> and weights <weight>" + // Печатает "Dog is <name> and weights <weight>" // "Dog is owned by <owner>" } ////////////////////////////////////////// -// Initialization and Operator Overloading +// Инициализация и перегрузка операторов. ////////////////////////////////////////// -// In C++ you can overload the behavior of operators such as +, -, *, /, etc. -// This is done by defining a function which is called -// whenever the operator is used. +// В C++ вы можете перегрузить поведение таких операторов: +, -, *, / и др.. +// Это делается путем определения функции, которая вызывается, +// когда используется оператор. #include <iostream> using namespace std; class Point { public: - // Member variables can be given default values in this manner. + // Значения по умолчанию для переменных-членов могут быть установлены + // следующим образом. double x = 0; double y = 0; - // Define a default constructor which does nothing - // but initialize the Point to the default value (0, 0) + // Определяем новый конструктор, который инициализирует Point со значениями + // по умолчанию (0, 0) Point() { }; - // The following syntax is known as an initialization list - // and is the proper way to initialize class member values + // Следующий синтаксис известен как список инициализации и является верным способом + // инициализировать значения членов класса. Point (double a, double b) : x(a), y(b) - { /* Do nothing except initialize the values */ } + { /* Ничего не делайте кроме инициализации значений */ } - // Overload the + operator. + // Перегружаем оперот +. Point operator+(const Point& rhs) const; - // Overload the += operator + // Перегружаем оператор +=. Point& operator+=(const Point& rhs); - // It would also make sense to add the - and -= operators, - // but we will skip those for brevity. + // Имеет смысл добавить перегрузку операторов - и -=, + // но для краткости мы опустим эти детали. }; Point Point::operator+(const Point& rhs) const { - // Create a new point that is the sum of this one and rhs. + // Создает новую точку, которая является суммой этой точки и rhs. return Point(x + rhs.x, y + rhs.y); } @@ -558,59 +555,58 @@ Point& Point::operator+=(const Point& rhs) int main () { Point up (0,1); Point right (1,0); - // This calls the Point + operator - // Point up calls the + (function) with right as its parameter + // Здесь происходит вызов оператора + класса Point + // Точка "up" вызывает + (функция) с параметром "right" Point result = up + right; - // Prints "Result is upright (1,1)" + // Печатает "Result is upright (1,1)" cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; return 0; } ///////////////////// -// Templates +// Шаблоны ///////////////////// -// Templates in C++ are mostly used for generic programming, though they are -// much more powerful than generic constructs in other languages. They also -// support explicit and partial specialization and functional-style type -// classes; in fact, they are a Turing-complete functional language embedded -// in C++! +// Шаблоны в С++, в основном, используются для обобщенного программирования, хотя +// они гораздо более мощны чем дженерики в других языках. Они также поддерживают +// явные, частные и функциональные типы классов; на самом деле, они являются +// тьюринг-полным языком встроенным в C++! -// We start with the kind of generic programming you might be familiar with. To -// define a class or function that takes a type parameter: +// Мы начнем с наиболее распространенного типа обобщенного программирования. Чтобы +// определить класс или функцию, которая принимает параметр типа: template<class T> class Box { public: - // In this class, T can be used as any other type. + // В этом классе T может быть любого типа. void insert(const T&) { ... } }; -// During compilation, the compiler actually generates copies of each template -// with parameters substituted, so the full definition of the class must be -// present at each invocation. This is why you will see template classes defined -// entirely in header files. +// Во время компиляции, компилятор фактически генерирует копии каждого шаблона +// с замещенными параметрами, по-этому полное определение класса должно присутствовать +// при каждом вызове. Именно по-этому классы шаблонов полностью определены в +// заголовочных файлах. -// To instantiate a template class on the stack: +// Чтобы создать экземпляр класса шаблона на стеке: Box<int> intBox; -// and you can use it as you would expect: +// и вы можете использовать его, как и ожидалось: intBox.insert(123); -// You can, of course, nest templates: +// Вы, конечно, можете использовать вложенные шаблоны: Box<Box<int> > boxOfBox; boxOfBox.insert(intBox); -// Until C++11, you had to place a space between the two '>'s, otherwise '>>' -// would be parsed as the right shift operator. +// Вплоть до С++11, вы должны были ставить пробел между двумя символами '>', иначе '>>' +// принимался парсером, как оператор правого сдвига. -// You will sometimes see +// Иногда вы можете увидеть // template<typename T> -// instead. The 'class' keyword and 'typename' keywords are _mostly_ -// interchangeable in this case. For the full explanation, see +// вместо этого. В этом случае, ключевые слова 'class' и 'typename' _в основном_ +// взаимозаменяемыми. Для более подробной информации смотрите // http://en.wikipedia.org/wiki/Typename -// (yes, that keyword has its own Wikipedia page). +// (да-да, это ключевое слово имеет собственную страничку на вики). -// Similarly, a template function: +// Аналогичным образом, шаблонная функция: template<class T> void barkThreeTimes(const T& input) { @@ -619,115 +615,115 @@ void barkThreeTimes(const T& input) input.bark(); } -// Notice that nothing is specified about the type parameters here. The compiler -// will generate and then type-check every invocation of the template, so the -// above function works with any type 'T' that has a const 'bark' method! +// Обратите внимание, что здесь ничего не указано о типе параметра. Компилятор +// будет генерировать и затем проверять тип каждый вызов шаблона, по-этому +// данная функция работает с любым типом 'T', который имеет метод 'bark'. Dog fluffy; fluffy.setName("Fluffy") -barkThreeTimes(fluffy); // Prints "Fluffy barks" three times. +barkThreeTimes(fluffy); // Печатает "Fluffy barks" три раза. -// Template parameters don't have to be classes: +//Параметры шаблона не должны быть классами: template<int Y> void printMessage() { cout << "Learn C++ in " << Y << " minutes!" << endl; } -// And you can explicitly specialize templates for more efficient code. Of -// course, most real-world uses of specialization are not as trivial as this. -// Note that you still need to declare the function (or class) as a template -// even if you explicitly specified all parameters. +// В конце концов, вы можете явно специализировать шаблоны для более эффективного +// кода. Конечно, большинство реальных случаев использования специализации +// не так тривиально, как это. Обратите внимание, вам все еще нужно явно объявить +// функцию (или класс) в качестве шаблона, даже если вы явно указали все параметры. template<> void printMessage<10>() { cout << "Learn C++ faster in only 10 minutes!" << endl; } -printMessage<20>(); // Prints "Learn C++ in 20 minutes!" -printMessage<10>(); // Prints "Learn C++ faster in only 10 minutes!" +printMessage<20>(); // Печатает "Learn C++ in 20 minutes!" +printMessage<10>(); // Печатает "Learn C++ faster in only 10 minutes!" ///////////////////// -// Exception Handling +// Обработка исключений ///////////////////// -// The standard library provides a few exception types -// (see http://en.cppreference.com/w/cpp/error/exception) -// but any type can be thrown an as exception +// Стандартная библиотека предоставляет несколько типов исключений +// (смотрите http://en.cppreference.com/w/cpp/error/exception) +// но, в принципе, любой тип может быть брошен в качестве исключения. #include <exception> #include <stdexcept> -// All exceptions thrown inside the _try_ block can be caught by subsequent -// _catch_ handlers. +// Все исключения брошены внутри блока _try_ могут быть пойманы в последующем блоке +// _catch_. try { - // Do not allocate exceptions on the heap using _new_. + // Не выделяйте память в куче для исключений с помощью ключевого слова _new_. throw std::runtime_error("A problem occurred"); } -// Catch exceptions by const reference if they are objects +// Поймайте исключение по константной ссылке, если они являются объектами catch (const std::exception& ex) { std::cout << ex.what(); } -// Catches any exception not caught by previous _catch_ blocks +// Ловит любое исключение не пойманное предыдущим блоком _catch_ catch (...) { std::cout << "Unknown exception caught"; - throw; // Re-throws the exception + throw; // Повторный выброс исключения } /////// -// RAII +// Получение ресурса есть инициализация (RAII) /////// -// RAII stands for "Resource Acquisition Is Initialization". -// It is often considered the most powerful paradigm in C++ -// and is the simple concept that a constructor for an object -// acquires that object's resources and the destructor releases them. +// Программная идиома объектно-ориентированного программирования, смысл которой +// заключается в том, что с помощью тех или иных программных механизмов получение +// некоторого ресурса неразрывно совмещается с инициализацией, а освобождение - +// с уничтожением объекта. -// To understand how this is useful, -// consider a function that uses a C file handle: +// Чтобы понять на сколько это полезно, +// рассмотрим функцию, которая использует обработчик файлов в С: void doSomethingWithAFile(const char* filename) { - // To begin with, assume nothing can fail. + // Для начала, предположим, ничего не может потерпеть неудачу. - FILE* fh = fopen(filename, "r"); // Open the file in read mode. + FILE* fh = fopen(filename, "r"); // Открываем файл в режиме чтения. doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); - fclose(fh); // Close the file handle. + fclose(fh); // Закрываем обработчик файла. } -// Unfortunately, things are quickly complicated by error handling. -// Suppose fopen can fail, and that doSomethingWithTheFile and -// doSomethingElseWithIt return error codes if they fail. -// (Exceptions are the preferred way of handling failure, -// but some programmers, especially those with a C background, -// disagree on the utility of exceptions). -// We now have to check each call for failure and close the file handle -// if a problem occurred. +// К сожалению, вещи быстро осложняется обработкой ошибок. +// Предположим fopen может потерпеть неудачу, тогда doSomethingWithTheFile и +// doSomethingElseWithIt вернут коды ошибок если потерпят неудачу. +// (Исключения являются предпочтительным способом обработки ошибок, +// но некоторые программисты, особенно те, кто имеет большой опыт работы с С, +// не согласны с аргументами о полезности исключений). +// Теперь мы должны проверить каждый вызов на наличие ошибок и закрыть обработчик +// файла если таковы есть. bool doSomethingWithAFile(const char* filename) { - FILE* fh = fopen(filename, "r"); // Open the file in read mode - if (fh == nullptr) // The returned pointer is null on failure. - return false; // Report that failure to the caller. + FILE* fh = fopen(filename, "r"); // Открывает файл в режиме чтения + if (fh == nullptr) // В случае неудачи возвращаемый указатель принимает null. + return false; // Сообщает об неудаче вызывающему. - // Assume each function returns false if it failed + // Предположим, каждая функция возвращает false в случае неудачи if (!doSomethingWithTheFile(fh)) { - fclose(fh); // Close the file handle so it doesn't leak. - return false; // Propagate the error. + fclose(fh); // Закрываем обработчик файл чтобы не было утечек + return false; // Сообщает об ошибке. } if (!doSomethingElseWithIt(fh)) { - fclose(fh); // Close the file handle so it doesn't leak. - return false; // Propagate the error. + fclose(fh); // Закрываем обработчик файл чтобы не было утечек + return false; // Сообщает об ошибке. } - fclose(fh); // Close the file handle so it doesn't leak. - return true; // Indicate success + fclose(fh); // Закрываем обработчик файл чтобы не было утечек + return true; // Указывает на успех } -// C programmers often clean this up a little bit using goto: +// C-программисты часто упорядочивают это с помощью goto: bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); @@ -741,18 +737,18 @@ bool doSomethingWithAFile(const char* filename) goto failure; fclose(fh); // Close the file - return true; // Indicate success + return true; // Указывает на успех failure: fclose(fh); - return false; // Propagate the error + return false; // Сообщает об ошибке. } -// If the functions indicate errors using exceptions, -// things are a little cleaner, but still sub-optimal. +// Если функции указывают на ошибки с помощью исключений, вещи становятся проще, +// но все еще не оптимальны. void doSomethingWithAFile(const char* filename) { - FILE* fh = fopen(filename, "r"); // Open the file in read mode + FILE* fh = fopen(filename, "r"); // Открываем файл в режиме чтения if (fh == nullptr) throw std::runtime_error("Could not open the file."); @@ -761,52 +757,51 @@ void doSomethingWithAFile(const char* filename) doSomethingElseWithIt(fh); } catch (...) { - fclose(fh); // Be sure to close the file if an error occurs. - throw; // Then re-throw the exception. + fclose(fh); // Убедитесь, что закрываете файл, если происходит ошибка. + throw; // Затем повторно бросает исключение. } fclose(fh); // Close the file - // Everything succeeded + // Успех } -// Compare this to the use of C++'s file stream class (fstream) -// fstream uses its destructor to close the file. -// Recall from above that destructors are automatically called -// whenever an object falls out of scope. +// Сравните это с использованием класса потока файла (fstream) в С++, который +// использует свой деструктор чтобы закрыть файл. Еще раз взгляните выше, +// деструктор вызывается автоматически, когда объект выпадает из области видимости. void doSomethingWithAFile(const std::string& filename) { - // ifstream is short for input file stream - std::ifstream fh(filename); // Open the file + // ifstream определяет файловый поток + std::ifstream fh(filename); // Открыть файл - // Do things with the file + // Что-то делать с файлом doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); -} // The file is automatically closed here by the destructor - -// This has _massive_ advantages: -// 1. No matter what happens, -// the resource (in this case the file handle) will be cleaned up. -// Once you write the destructor correctly, -// It is _impossible_ to forget to close the handle and leak the resource. -// 2. Note that the code is much cleaner. -// The destructor handles closing the file behind the scenes -// without you having to worry about it. -// 3. The code is exception safe. -// An exception can be thrown anywhere in the function and cleanup -// will still occur. - -// All idiomatic C++ code uses RAII extensively for all resources. -// Additional examples include -// - Memory using unique_ptr and shared_ptr -// - Containers - the standard library linked list, -// vector (i.e. self-resizing array), hash maps, and so on -// all automatically destroy their contents when they fall out of scope. -// - Mutexes using lock_guard and unique_lock - -// containers with object keys of non-primitive values (custom classes) require -// compare function in the object itself or as a function pointer. Primitives -// have default comparators, but you can override it. +} // Здесь файл автоматически закрывается в деструкторе. + +// Это имеет _огромнейшие_ преимущества: +// 1. Неважно, что произойдет, +// ресурсы (в данном случае обработчик файлов) будут очищены. +// После того, как вы правильно напишите деструктор, +// Больше будет _не возможно_ закрыть обработчик файлов или допустить утечку. +// 2. Обратите внимание, что код намного проще. +// Деструктор закрывает файловый поток "за кулисами" и вам больше не нужно об +// этом беспокоится. +// 3. Код устойчив к исключениям. +// Исключение может быть брошено в любом месте в функции и это никак не повлияет +// на очистку. + +// Весь идиоматический код на С++ широко использует RAII для всех ресурсов. +// Дополнительные примеры включат +// - Использование памяти unique_ptr и shared_ptr +// - Контейнеры - стандартная библиотека связанных списков, векторы +// (т.е. самоизменяемые массивы), хэш-карты и все остальное автоматически +// уничтожается сразу-же, когда выходит за пределы области видимости. +// - Ипользование мютексов lock_guard и unique_lock + +// Контейнеры с пользовательскими классами в качестве ключей требуют +// функций-компаратор в самом объекте или как указатель на функцию. Примитивы +// имеют компараторы по умолчанию, но вы можете перегрузить их. class Foo { public: int j; @@ -817,81 +812,82 @@ struct compareFunction { return a.j < b.j; } }; -//this isn't allowed (although it can vary depending on compiler) -//std::map<Foo, int> fooMap; +// это не допускается (хотя это может варьироваться в зависимости от компилятора) +// std::map<Foo, int> fooMap; std::map<Foo, int, compareFunction> fooMap; fooMap[Foo(1)] = 1; fooMap.find(Foo(1)); //true ///////////////////// -// Fun stuff +// Веселые вещи ///////////////////// -// Aspects of C++ that may be surprising to newcomers (and even some veterans). -// This section is, unfortunately, wildly incomplete; C++ is one of the easiest -// languages with which to shoot yourself in the foot. +// Аспекты С++, которые могут быть удивительными для новичком (и даже для некоторых +// ветеранов). Этот раздел, к сожалению, очень неполон. С++ является одним из самых +// простых языков, где очень легко выстрелить себе в ногу. -// You can override private methods! +// Вы можете перегрузить приватные методы! class Foo { virtual void bar(); }; class FooSub : public Foo { - virtual void bar(); // Overrides Foo::bar! + virtual void bar(); // Перегружает Foo::bar! }; -// 0 == false == NULL (most of the time)! +// 0 == false == NULL (в основном)! bool* pt = new bool; -*pt = 0; // Sets the value points by 'pt' to false. -pt = 0; // Sets 'pt' to the null pointer. Both lines compile without warnings. +*pt = 0; // Устанавливает значение указателя 'pt' в false. +pt = 0; // Устанавливает значение 'pt' в нулевой указатель. Обе линии проходят + // компиляцию без ошибок. -// nullptr is supposed to fix some of that issue: +// nullptr приходит на помощь: int* pt2 = new int; -*pt2 = nullptr; // Doesn't compile -pt2 = nullptr; // Sets pt2 to null. +*pt2 = nullptr; // Не пройдет компиляцию +pt2 = nullptr; // Устанавливает pt2 в null. -// There is an exception made for bools. -// This is to allow you to test for null pointers with if(!ptr), -// but as a consequence you can assign nullptr to a bool directly! -*pt = nullptr; // This still compiles, even though '*pt' is a bool! +// Существует исключение для булевых значений. +// Это позволит вам проверить указатели с помощью if(!ptr), +// но как следствие вы можете установить nullptr в bool напрямую! +*pt = nullptr; // Это по прежнему проходит компиляцию, даже если '*pt' - bool! // '=' != '=' != '='! -// Calls Foo::Foo(const Foo&) or some variant (see move semantics) copy -// constructor. +// Вызывает Foo::Foo(const Foo&) или некий вариант (смотрите "move semantics") +// копирования конструктора. Foo f2; Foo f1 = f2; -// Calls Foo::Foo(const Foo&) or variant, but only copies the 'Foo' part of -// 'fooSub'. Any extra members of 'fooSub' are discarded. This sometimes -// horrifying behavior is called "object slicing." +// Вызывает Foo::Foo(const Foo&) или вариант, но копирует только часть 'Foo' из +// 'fooSub'. Любые другие члены 'fooSub' пропускаются. Иногда это ужасное поведение +// называют "object slicing." FooSub fooSub; Foo f1 = fooSub; -// Calls Foo::operator=(Foo&) or variant. +// Вызывает Foo::operator=(Foo&) или вариант. Foo f1; f1 = f2; -// How to truly clear a container: +// Как по-настоящему очистить контейнер: class Foo { ... }; vector<Foo> v; for (int i = 0; i < 10; ++i) v.push_back(Foo()); -// Following line sets size of v to 0, but destructors don't get called -// and resources aren't released! +// В слудующей точке размер v устанавливается в 0, но деструктор не вызывается +// и не происходит очистка ресурсов! v.empty(); -v.push_back(Foo()); // New value is copied into the first Foo we inserted +v.push_back(Foo()); // Новые значения копируются в первый вставленный Foo -// Truly destroys all values in v. See section about temporary objects for -// explanation of why this works. +// Настоящие уничтожение всех значений v. Смотрите раздел о временном объекте +// для объяснения того, как это работает. v.swap(vector<Foo>()); ``` -Further Reading: +Дальнейшее чтение: -An up-to-date language reference can be found at +Наиболее полное и обновленное руководство по С++ можно найти на <http://cppreference.com/w/cpp> -Additional resources may be found at <http://cplusplus.com> +Дополнительные ресурсы могут быть найдены на <http://cplusplus.com> |