• Можно ли возвращать лямбды?

    Nipheris
    @Nipheris Куратор тега C++
    Добавлю пару примеров к сказанному MiiNiPaa:
    Вот такой код:
    auto GetLambda() {
        return []( const int &x ) { return x*x ; } ;
    }

    это синтаксический сахар для такого (все это можно было писать еще и до появления лямбд):
    struct Lambda {
    	int operator()(const int &x) { return x * x; }
    };
    Lambda GetLambda() {
    	return Lambda();
    }

    Отличие в том, что явно класс не создается, но принцип тот же. Возможно, на этом примере вам непонятно, зачем вся эта заморочка с классом. Поэтому рассмотрим другой пример. Этот код
    auto GetLambda(int y) {
    	return [y](const int &x) { return x*y; };
    }

    можно переписать так:
    struct Lambda {
    	int y;
    	Lambda(int y) : y(y) { }
    	int operator()(const int &x) { return x*y; }
    };
    Lambda GetLambda(int y) {
    	return Lambda(y);
    }

    Как видите, захват значения локальной переменной и "сопровождение" им кода лямбды осуществляется с помощью оборачивания в класс. Если еще не знакомились с замыканиями, самое время это сделать.
    Ответ написан
    Комментировать
  • Можно ли возвращать лямбды?

    @MiiNiPaa
    Вот так делать - это нормально?
    Вполне

    И что в таком случае возвращается, указатель на функцию или сама функция?
    Функциональный объект. Лямбда — не функция, она может быть приведена к указателю на функцию в некоторых случаях.

    Если возвращается указатель, то где хранится сама функция, в куче или стеке?
    «Функция» лямбды хранится там же, где и остальной код. На лету ничего не собирается и не компилируется. Лямбда это синтаксический сахар для объявления класса с перегруженым оператором вызова функции.

    И еще один вопрос, по этой же теме:
    Это сокращенная запись вот такой конструкции:
    Или что то другое?
    lambda имеет уникальный тип. Это не функция (но может быть приведена к ней в данном случае).
    Ответ написан
    Комментировать
  • {} при инициализаци массива массивов?

    @MiiNiPaa
    Вообще, оно не должно компилироваться вообще. Размеры массивов должны быть константными выражениями.

    То что у вас — расширение компилятора. Не работает в С++14 скорее всего потому, что в С++11 компилятор использует собственное расширение основанное на сишных VLA. А в С++14 — более ограниченные С++ ARB, которые могли войти в С++14, но не вошли.
    Ответ написан
    2 комментария
  • Приведение обьекта производного класса к базовому?

    Nipheris
    @Nipheris Куратор тега C++
    поля объявленные в производном классе исчезают?

    Это называется object slicing. Это явление проявляется в языках, где сложные типы данных вроде классов и записей а) могут наследоваться и добавлять новые поля при наследовании; б) могут присваиваться по-значению (by value). Это и приводит к тому, что поля потомка при присвоении в переменную типа предка отсекаются. Такое присвоение само по себе некорректно, т.к. если вы работаете с объектами классов-наследников через интерфейс базового класса, это подразумевает полиморфное поведение и работу через ссылку/указатель, т.е. чтобы вместо самого объекта копировалась ссылка/указатель на него (т.е. его identity, "уникальный ключ"), а сам оставался нетронутым и лежал там же, где и лежал.

    При работе через ССЫЛКУ на базовый класс (т.е. Base&) таких проблем не будет, однако ссылка сама по себе переменной не является (в отличие от указателя) - это лишь дополнительное ИМЯ для некоторой другой переменной или области памяти. Поэтому, вы не сможете сохранить ссылку в векторе - ваш код не скомпилируется. В векторе вам нужно будет хранить указатели. Например, std::vector<Base*>.

    Запомните простое правило - если ваши объекты подразумевают работу через интерфейс базового класса (т.е. полимофрное поведение), то в большинстве случаев вам следует работать с ними через указатель (и, в большинстве случаев, размещать эти объекты в куче). В том числе через умные указатели (unique_ptr, shared_ptr).

    В других языках (C#, D вроде тоже) существует фундаментальное разделение на типы-значения и ссылочные типы, и для всех ссылочных типов работа "через ссылку" предоставляется автоматически. В C++ такого разделения нет, и как работать с типом вы выбираете сами, при его ИСПОЛЬЗОВАНИИ (т.е. используете либо по-значению, либо через указатель).

    P.S. С днем рождения!
    Ответ написан
    1 комментарий
  • Приведение обьекта производного класса к базовому?

    @Mercury13
    Программист на «си с крестами» и не только
    Через указатели и ссылки — останется.
    По значению (как у тебя сейчас в векторе) — преобразуется в базовый.

    Главная проблема работы с указателями и ссылками — где хранить объекты и как их уничтожать. Хранят обычно в «куче», а для уничтожения используют умные указатели или что-то самописное под задачу. Вот, например, решение на умных указателях C++11:
    #include <iostream>
    #include <memory>
    #include <vector>
    
    class Base{
    public:
        // Нужен виртуальный деструктор, ведь мы будем уничтожать детей
        // через родительский ук-ль. Да и dynamic_cast требует RTTI,
        // а значит, хоть одного виртуального.
        virtual ~Base() = default;
    };
    
    class Exp: public Base
    {
    int i=0;
    public:
           int Get() const {  return i; }
           void Set(const int &num) { i=num; }
    };
    
    std::vector<std::shared_ptr<Base>> MyStack;
    Base &GetRef() { return **MyStack.begin();  }
    
    int main() {
        std::shared_ptr<Exp> a = std::make_shared<Exp>();
        a->Set(4);
        MyStack.push_back(a);
        int res=dynamic_cast<Exp&>(GetRef()).Get(); // Теперь работает
        std::cout << res << std::endl;;
    }
    Ответ написан
    Комментировать
  • Функциональное приведение типов?

    Tiendil
    @Tiendil
    Разработчик ПО.
    Вот пары эквивалентных примеров
    // Что то вроде 0.3333333
    std::cout<< (double) 1 / 3 ; 
    std::cout<< double(1) / 3 ;


    std::cout<< double (1 / 3) ; 
    std::cout<< (double) (1 / 3) ;
    Ответ написан
    Комментировать
  • Функциональное приведение типов?

    @iv_k
    напишите (1.0/3.0)
    а у вас инт делится на инт и получается 0
    Ответ написан
    Комментировать
  • Функциональное приведение типов?

    @res2001
    Developer, ex-admin
    В первом случае сначала приводится 1 к double явно, потом неявно 3 в double, т.к. первый аргумент операции дабл, а потом выполняется деление двух даблов.
    Во втором случае выполняется целочисленное деление с результатом 0, затем 0 приводится к даблу.
    Ответ написан
    Комментировать
  • Умные указатели?

    @Xano
    Если Вы не знаете, зачем Вам умные указатели - они Вам не нужны.
    Наверное, самое важное их свойство - гарантия того, что объект не разрушится, пока есть умный указатель + возможность разрушения объекта в произвольном месте, когда он уже точно никому не нужен.
    Один из примеров, где умные указатели оправданы - использование нескольких потоков для выполнения операций с одним объектом.
    Ответ написан
    Комментировать
  • Умные указатели?

    Есть задачи, которые не имеют решения на ссылках (либо это решение в разы хуже, чем если бы мы использовали указатели).
    Пример: паттерн стратегия
    #include <iostream>
    #include <memory>
    
    class Strategy {
    public:
        virtual void doAction() = 0;
    };
    
    class FirstStrategy : public Strategy{
    public:
        void doAction() override {
            std::cout << "First" << std::endl;
        }
    };
    
    class SecondStrategy : public Strategy{
    public:
        void doAction() override {
            std::cout << "Second" << std::endl;
        }
    };
    
    class A {
        std::shared_ptr<Strategy> behavior;
    
    public:
        void setBehavior(std::shared_ptr<Strategy> b) {
            behavior = b;
        }
    
        void doBehavior() {
            behavior->doAction();
        }
    
    };
    
    int main() {
        A a;
        a.setBehavior(std::make_shared<FirstStrategy>());
        a.doBehavior();
    
        a.setBehavior(std::make_shared<SecondStrategy>());
        a.doBehavior();
        return 0;
    }


    Во время исполнения стратегия может меняться. Так как ссылку изменить нельзя, придется создавать какие-то костыли. С указателями все проще: просто обновляем значение переменной
    Ответ написан
    Комментировать
  • Вызов копирующего конструктора?

    Сначала вызов конструктора для создания временного объекта, затем вызов конструктора копирования из временного объекта в тот, что определён слева. Но компилятор может оптимизировать до 1 вызова, если конструктор копирования явно не определён.
    Ответ написан
    2 комментария
  • Магия конструкторов?

    Компилятор не делаем больше одного преобразования
    Если заменить на Example two=std::string("line");, то все заработает
    Example two=std::string("line");  ->  Example two(std::string("line")); //подходит конструктор Example ( const std::string &line )

    Example two="line";  ->  Example two("line"); //Нет конструктора, который принимает const char*
    Ответ написан
    Комментировать
  • Ссылки на функции?

    AtomKrieg
    @AtomKrieg
    Давай я поищу в Google за тебя
    Ссылки по внутреннему устройству это указатели, поэтому их часто можно использовать в таких же целях. Они безопаснее и удобнее, но есть ограничения. Ограничения накладывает компилятор.
    int a= 10;
    int& b = a; //int *b = &a;
    b = 5;      //*b = 5; 
    
    cout << a << endl;
    Ответ написан
    Комментировать
  • Ссылки на функции?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    почему примеров его использования нигде не заметно, удобнее ведь вместо константного указателя.

    Чем удобнее-то? Ссылку нужно инициализировать в момент создания и нельзя изменить потом. Функцию в C++ нельзя создать или вернуть из функции, зачем ссылка?
    Ответ написан
    3 комментария
  • Если поставить MS Office 2010 поверх MS Office 2007, то лицензия останется?

    s0ci0pat
    @s0ci0pat
    I'm Awesome
    Лицензия не сохраниться, даже если ты поставишь расширенную версию 2007 с Publisher
    Ответ написан
    Комментировать
  • Указатели на память в стеке?

    @res2001
    Developer, ex-admin
    Почему при выводе, например
    std :: cout << cStr ;
    Выводится "string" , то есть значение, а не адрес значения как обычно с указателями ?

    Потому что в cout переопределена оператор << для типа char*, так чтобы выводилась именно строка, а не указатель. Чтоб вывести адрес преобразуйте указатель в int и выводите как целое число.
    Ответ написан
    Комментировать
  • Указатели на память в стеке?

    gbg
    @gbg Куратор тега C++
    Любые ответы на любые вопросы
    Итак. В присваивании у нас участвует "string" - это константа. Она отправляется компилятором в область данных программы - это зависит от платформы, куда конкретно. Так что на стеке оказывается сам указатель cStr, который указывает куда-то, куда компилятор засунул ваши буковки.

    По второму вопросу (какого черта вы засунули два вопроса в один?) - компилятор - не дурак, он взял два одинаковых набора символов "str", понял, что они одинаковые, и не стал плодить дубляки - в a и b попадает один указатель, потому как компилятор не стал сохранять в программе две идентичные строки.
    Ответ написан
    7 комментариев
  • Неявное наследование private ?!?

    Nipheris
    @Nipheris Куратор тега C++
    Вы невнимательно читали про наследование (или читали в плохом источнике).

    Логически (т.е. с точки зрения самой идеи) наследование (причем, любое, public и другие) подразумевает, что реализация базового класса станет частью реализации дочернего. Приватные поля класса - это часть его реализации.

    Технически, наследование в C++ подразумевает наличие подобъекта базового класса в объекте класса-наследника. Т.е. у вас в каждый объект Two помимо его собственных полей (в вашем примере их нет) запихиваются все поля Base (и так с каждым базовым классом, если их несколько), по принципу матрешки. НЕВАЖНО, как указали уже в первом ответе, что вы не имеете к ним доступ из класса-наследника. Важно, что они есть, и методы класса Base могут ими спокойно пользоваться, чтобы выполнять свою работу.
    Ответ написан
    Комментировать
  • Что не так со словом virtual?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    std::string Get()
        {
            /// Приводим this к A* и вызываем Get, удаляя первый символ
            return ( ( A* ) this ) -> Get () .erase (0, 1); 
        }

    Получил бесконечную рекурсию, потому что ((A*)this)->Get() -- полиморфный вызов, потому что Get в классе A определён как virtual. Т.е. ты возьмёшь из таблицы виртуальных функций подобъекта A указатель на виртуальную функцию Get, а он указывает на B::Get.
    Если хочешь вызвать метод класса А -- так и пиши:
    struct B : public A
    {
        /// Переопределяем метод Get
        std::string Get()
        {
            return A::Get () .erase (0, 1); 
        }
    };
    Ответ написан
    Комментировать
  • Возможно ли в C++ повторное выделение памяти в стеке под переменную?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    В древнем Borland C++ Builder 5
    Исходный код:
    struct Example {
      int a;
    };
    
    void main() {
      Example ex;
      ex.a = 1;
      ex = Example();
      ex.a = 2;
    }

    Трансляция в ассемблер:
    @_main	proc	near
    	push      ebp
    	mov       ebp,esp
    	add       esp,-8
    	mov       dword ptr [ebp-4],1
    	mov       eax,dword ptr [ebp-8]
    	mov       dword ptr [ebp-4],eax
    	mov       dword ptr [ebp-4],2
    	mov       esp,ebp
    	pop       ebp
    	ret 
    @_main	endp

    Видно, что в начале функции в стеке было зарезервировано место под две копии структуры.
    Изменим код
    struct Example {
      int a;
    };
    
    void main(){
      Example ex;
      ex.a = 1;
      for (int i = 0; i < 10; i++) {
        ex = Example();
        ex.a = i;
      }
    }

    Ассемблер:
    @_main	proc	near
    	push      ebp
    	mov       ebp,esp
    	add       esp,-12
    	mov       dword ptr [ebp-4],1
    	xor       eax,eax
    	mov       dword ptr [ebp-8],eax
    @3: mov       edx,dword ptr [ebp-12]
    	mov       dword ptr [ebp-4],edx
    	mov       ecx,dword ptr [ebp-8]
    	mov       dword ptr [ebp-4],ecx
    	inc       dword ptr [ebp-8]
    	cmp       dword ptr [ebp-8],10
    	jl        short @3
    	mov       esp,ebp
    	pop       ebp
    	ret 
    @_main	endp

    Опять таки, несмотря на цикл в стеке было зарезервировано место под две структуры, в цикле в переменную каждый раз копируется вторая структура.
    Ответ написан
    3 комментария