Участник:Yulya3102/Плюсы2сем — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(l-value, r-value)
(перегрузка операторов)
Строка 141: Строка 141:
  
 
=== перегрузка операторов ===
 
=== перегрузка операторов ===
 +
[http://habrahabr.ru/post/132014/]
 +
 
=== оператор присваивания ===
 
=== оператор присваивания ===
 
=== разница между конструктором копирования и оператором присваивания ===
 
=== разница между конструктором копирования и оператором присваивания ===

Версия 11:52, 9 марта 2013

Содержание

i8086

регистры общего назначения, сегментные регистры, регистр флагов

некоторые распространенные команды

команды для работы со стеком

соглашения вызова функций

32-битные регистры

stack frame

ошибки: возврат указателя на локальную переменную из функции, buffer-overrun для объектов в стеке

stack-smash protector

toolchain: препроцессор, транслятор, компоновщик

модификатор static

Local scope

//область видимости — блок

while (true)
{
    static int i = 0;
    i++;
}

Переменная i будет создана лишь один раз, и её значение будет храниться в течение всего времени выполнения программы, несмотря на выход за пределы области видимости. Тот же пример с выводом для наглядности.

Function scope

//область видимости — функция

void foo()
{
    static int i = 0;
    i++;
}

Аналогично, переменная i сохраняется между вызовами foo(), но видна только в пределах блока, в котором определена.

File scope

//область видимости — файл

static int global_static_local_to_this_file;

Очевидно, эта переменная будет видна повсюду в файле и только в нём.

Class scope

//область видимости — класс

Статические данные можно получить так же, как и нестатические, с помощью операторов . и ->. Но к ним также можно обращаться с помощью оператора ::, используя имя класса. Очевидно, создание объекта данного класса в данном случае не требуется.

Статические данные разделяются между всеми экземплярами класса.

Зачем это нужно? Например, так можно создать синглтон:

class singleton
{
    private:
        singleton(){}
    public:
        static singleton& instance()
        {
            static singleton inst;
            return inst;
        }
};

Объявление статической переменной внутри определения класса не является её определением. Если не инициализировать значение статической переменно, то по умолчанию будет присвоено значение 0. Внутри определения класса можно инициализировать переменные типов int, char, long, bool, а так же типов из пространства std.

Статические переменные не могут содержаться в локальных классах и не могут быть mutable.

Статические методы не имеют указателя this, поэтому в таких методах нельзя обращаться к нестатическим данным класса. К статическим методам можно обращаться через . и -> по имени объекта и по имени класса через ::.

Статические методы не могут быть виртуальными, не могут быть const и volatile. Локальные класса не могут содержать статические методы.

модификатор inline

Если часто повторяется обращение к очень маленькой функции, то стоит задуматься о стоимости вызова функции. Можно рассмотреть возможность спецификации функции как inline-подставляемой. В этом случае компилятор сгенерирует для функции соответствующий код в месте её вызова.

Для того, чтобы указать компилятору на своё желание сделать функцию inline-подставляемой, нужно поставить ключевое слово inline или включить определение функции в описание класса.

one definition rule (ODR)

Вкратце, положения ODR выглядят так:

  1. В пределах любой единицы трансляции шаблон, тип данных, функция, или объект не могут иметь более одного определения. Некоторые могут иметь неограниченное число объявлений. Определение порождает сущность.
  2. В пределах программы (совокупности всех единиц трансляции) объект или не-inline функция не могут иметь больше одного определения; если объект или функция используются, у каждого из них должно быть строго по единственному определению. Можно объявить объект или функцию, которые не будут использованы в программе, в этом случае не потребуется и их определения. Ни в коем случае не должно быть более одного определения.
  3. Некоторые сущности, например, типы, шаблоны или внешние inline функции, могут определяться в более чем одной единице трансляции. Для данной сущности, каждое определение должно быть одним и тем же. Объекты или функции, не являющиеся внешними, в разных единицах трансляции имеют разные сущности, даже если их имена и типы совпадают.

Некоторые нарушения ODR могут быть обнаружены компилятором. Остальные, а это в первую очередь касается программ, состоящих из нескольких небольших файлов, пропускаются (программист должен самостоятельно о них позаботиться).

Например:

 // file1.c:
     int a = 1;
     int b = 1;
     extern int c;
 // file2.c:
     int a;
     extern double b;
     extern int c;

В данном примере 3 ошибки: a определено дважды (int a; является определением, которое означает int a=0;), b описано дважды с разными типами, а c описано дважды, но не определено. Эти виды ошибок (ошибки компоновки) не могут быть обнаружены компилятором, который за один раз видит только один файл. Компоновщик, однако, их обнаруживает.

классы

TODO: union?

Класс — пользовательский тип, объявленный с помощью struct, class или union.


TODO: А что вообще тут ещё может быть?

конструкторы

Конструктор вызывается при создании объекта для его инициализации. Обозначается как одноимённая классу функция, не имеющая типа возвращаемого значения. Класс может иметь сколько угодно конструкторов с разными наборами параметров. Конструктор без параметров (или все аргументы которого имеют параметры по умолчанию) называется конструктором по умолчанию, а конструктор с первым параметром-ссылкой на тот же класс — конструктором копирования.

Array a(5); // вызывается Array::Array(int)
Array b;    // вызывается Array::Array()
Array c(a); // вызывается Array::Array(const Array&)
Array d=a;  // вызывается Array::Array(const Array&)
b=c;        // происходит вызов оператора =

Если в классе нет явно объявленных конструкторов, то он имеет неявно объявленный конструктор без параметров, который конструирует подобъекты классов-родителей и инициализирует поля класса с помощью конструкторов по умолчанию.

Конструктор копирования также неявно объявляется при отсутствии явного. Он выполняет копирование всех объявленных полей с помощью соответствующих конструкторов копирования.

Конструкторы не могут быть виртуальными.

деструкторы

Деструктор вызывается для уничтожения объекта класса. Обозначается как имя класса, перед которым ставится тильда. Деструктор не имеет типа возвращаемого значения и принимаемых аргументов. Класс может иметь только один деструктор.

Если деструктор не объявлен явно, то класс имеет неявно объявленный деструктор.

Деструктор может быть виртуальным (и обычно так и объявляется, чтобы гарантировать правильное уничтожение доступного по ссылке или указателю объекта независимо от того, какого типа ссылка или указатель).

const

Переменные

Очевидно, const переменные — это переменные, которые нельзя менять. Инициализируются в момент объявления.

const int p = 1; //инициализация в момент объявления, всё ок
const int q;
q = 5;           //а вот так уже нельзя

Функции-члены класса

Такие функции не могут менять поля класса, не объявленные как static или mutable, не могут возвращать не const ссылки и указатели на поля класса и не могут вызывать неконстантные функции класса.

ссылки

разница между ссылками и указателями

[1]

l-value, r-value

[2]

перегрузка операторов

[3]

оператор присваивания

разница между конструктором копирования и оператором присваивания

список инициализации

порядок инициализации/разрушения полей класса

Поля инициализируются в том порядке, в котором они объявлены, даже если в списке инициализации они указаны в другом порядке. Разрушаются в порядке, обратном порядку объявления.

volatile

директивы препроцессора

#include <>

#include ""

#define

#if

#else

#endif

#elif

#ifdef

#ifndef

#undef

include guards

#pragma once

#pragma once vs include guards

preprocessor pitfalls

[4]

циклический экспанд макросов

циклические зависимости на хедерах

неполные типы

[5]

name mangling

перегрузка функций

исключения

RAII

гарантии безопасности исключений

extern "C"

исключения в конструкторах

исключения в деструкторах

stack unwinding

возврат объектов из функции по значению, RVO

передача аргументов по значению, r-value/l-value

callback'и, способы фиксации аргументов у callback'ов

наследование, виртуальные функции, таблицы виртуальных функций

dynamic_cast

проблемы сишного typecast'а с неполными типами и несколькими базами, static_cast

const_cast, reinterpret_cast

зачем нужно виртуальное наследование (несколько баз с разными адресами у одного класса, typecast'ы, исключения)

виртуальное наследование

зачем нужны namespace'ы

namespace'ы, using declaration, using directive, namespace aliases

перегрузка операторов, ADL

зачем нужны шаблоны

базовое представление о шаблонах

два способа реализации шаблонов: Cfront-like, Borland-like, преимущества и недостатки обоих

специализация, частичная специализация

type_traits'ы

This header defines a series of classes to obtain type information on compile-time.

The header contains: Helper classes: Standard classes to assist in creating compile-time constants. Type traits: Classes to obtain characteristics of types in the form of compile-time constant values. Type transformations: Classes to obtain new types by applying specific transformations to existing types.

Контейнеры STL

Sequences: vector, list, deque

Associative Containers: [unordered][_multi]{set/map}

Итераторы, категории итераторов (Input, Output, Forward, Bidirectional, Random Access)

Примеры алгоритмов

find, find_if, search

remove, remove_if, прием с erase/remove_if

sort, stable_sort, partial_sort, nth_element

Много разговоров на тему того, что хоть явных ограничений на параметры шаблона нет, это не означает что их нет совсем.

копируемость/присваиваемость

требования к operator==

требования к operator<

согласованность operator== и operator<

разница между операторами внутри класса и снаружи (неявное приведение типов)

safe-bool

использование type_traits: SFINAE, tag-dispatching на примере STL

two-phase name lookup

STL: back-inserter, lower_bound, heap_*, priority_queue

const на примере STL

Concepts

anonymous namespaces

You can declare an unnamed namespace as a superior alternative to the use of global static variable declarations.

namespace { namespace-body }

An unnamed-namespace-definition having the syntax shown above behaves as if it were replaced by:

namespace unique { namespace-body }
using namespace unique;

Each unnamed namespace has an identifier, assigned and maintained by the program and represented here by unique, that differs from all other identifiers in the entire program. For example:

// unnamed_namespaces.cpp
// C2872 expected
namespace { int i; }          // unique::i
void f() { i++; }             // unique::i++

namespace A {
   namespace {
       int i;      // A::unique::i
       int j;      // A::unique::j
   }
}

using namespace A;

void h()
{
   i++;            // C2872: unique::i or A::unique::i
   A::i++;         // C2872: A::i undefined
   j++;            // A::unique::j++
}

Unnamed namespaces are a superior replacement for the static declaration of variables. They allow variables and functions to be visible within an entire translation unit, yet not visible externally. Although entities in an unnamed namespace might have external linkage, they are effectively qualified by a name unique to their translation unit and therefore can never be seen from any other translation unit.