Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: возвращение объектов из функции  (Прочитано 30051 раз)
0 Пользователей и 1 Гость смотрят эту тему.
FeelUs
Участник

ru
Offline Offline
Пол: Мужской

« : 20-03-2011 13:42 » 

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

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

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

я пока нашел такое решение: взять адрес от этого промежуточного объекта, а потом его разыменовать
- работает

вопрос:
могу ли я быть уверен, что у этого промежуточного объекта деструктор не вызовется до того как я его передам в оператор присваивания таким образом?
что значит взять адрес от него, и где он находится?
можно ли решить данную проблему как-то более просто?

Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 20-03-2011 14:26 » 

Думаю, дело в несоответствии твоего конструктора копирования спецификации. Вероятно у тебя аргумент не const.

Код: (C++)
myclass(myclass &arg); // не верно

myclass(const myclass &arg); // верно


Добавлено через 7 минут и 57 секунд:
Только не надо путать присваивание и копирование! Это разные операции.

Добавлено через 4 минуты и 19 секунд:
Код: (C++)
#include <stdio.h>
#include <assert.h>

class myclass
{
public:
    int x;

    ~myclass()
    {
        printf("Destructor (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass(int x = 0) : x(x)
    {
        printf("Constructor (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass(const myclass &s) : x(s.x)
    {
        printf("Copy by ref (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass& operator=(const myclass &s)
    {
        assert(&s != this);

        x = s.x;
        printf("Assign by ref (0x%08x)\n", (unsigned int)(void*)this);
        return *this;
    }

    void print()
    {
        printf("Value (0x%08x): %d\n", (unsigned int)(void*)this, x);
    }
};

myclass func()
{
    myclass b(2);

    return b;
}

int main()
{
    myclass b(1);
    myclass a = b; // инициализация - используется конструктор копирования.
    a.print();

    a = func(); // присваивание - используется operator=.
    a.print();

    return 0;
}

Constructor (0xbfc40588)
Copy by ref (0xbfc40584)
Value (0xbfc40584): 1
Constructor (0xbfc4058c)
Assign by ref (0xbfc40584)
Destructor (0xbfc4058c)
Value (0xbfc40584): 2
Destructor (0xbfc40584)
Destructor (0xbfc40588)



Добавлено через 2 минуты и 23 секунды:
Рекомендую статьи:

1. Копирование и присваивание
https://club.shelek.ru/viewart.php?id=243
https://club.shelek.ru/viewart.php?id=244
https://club.shelek.ru/viewart.php?id=247
https://club.shelek.ru/viewart.php?id=258
https://club.shelek.ru/viewart.php?id=259

2. Оператор operator=
https://club.shelek.ru/viewart.php?id=260
https://club.shelek.ru/viewart.php?id=261
« Последнее редактирование: 20-03-2011 14:41 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
FeelUs
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 20-03-2011 16:13 » 

статьи пока еще не прочитал,

но у меня в примерно в такомже классе и оператор присваивания и конструктор копирования не соответствуют спецификации (нет const), но все равно вызываются как встроенные
и если поставить const то тоже ненадо никаких *& ставить между присваиванием и вызовом ф-ции

но класс у меня олицетворяет указатель на дерево
и при деструкторе оно должно удаляться
=>если окажется 2 указателя на одно и тоже дерево получится не хорошо
и при операторе приваивания у меня указатели просто меняются
а при копиКонструкторе исходный указатель становится NULL
=>у меня они не могут быть const

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

а мой c++ builder 6 выдал мне
Код:
Constructor <0x0012ff88>
Copy by ref <0x0012f f84>
Value <0x0012ff84>: 1
Constructor <0x0012ff4c>
Copy by ref <0x0012ff80>
Destructor <0x0012ff4c>
Assign by ref <0x0012ff84>
Destructor <0x0012ff80>
Value <0x0012ff84>: 2
Destructor <0x0012ff84>
Destructor <0x0012ff88>

Цитата
Только не надо путать присваивание и копирование! Это разные операции.
если вы имели ввиду оператор присваивания и конструктор копирования, то я вас понял
« Последнее редактирование: 20-03-2011 16:29 от FeelUs » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 20-03-2011 17:21 » 

FeelUs, огромная просьба: не торопись и выражай свои мысли яснее. И про правила языка не забывай.

Какой компилятор? Версия?
« Последнее редактирование: 20-03-2011 17:29 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
FeelUs
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 20-03-2011 18:23 » 

Код: (C++)
//---------------------------------------------------------------------------
#pragma hdrstop
//---------------------------------------------------------------------------

#include <stdio.h>
#include <assert.h>

class myclass
{
public:
    int x;

    ~myclass()
    {
        printf("Destructor (0x%08x)", (unsigned int)(void*)this);
        fgetc(stdin);
    }

    myclass(int x = 0) : x(x)
    {
        printf("Constructor (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass(const myclass &s) : x(s.x)
    {
        printf("Copy by ref (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass& operator=(const myclass &s)
    {
        assert(&s != this);

        x = s.x;
        printf("Assign by ref (0x%08x)\n", (unsigned int)(void*)this);
        return *this;
    }

    void print()
    {
        printf("Value (0x%08x): %d\n", (unsigned int)(void*)this, x);
    }
};

myclass func()
{
    myclass b(2);

    return b;
}

#pragma argsused
int main()
{
    myclass b(1);
    myclass a = b; // èíèöèàëèçàöèÿ - èñïîëüçóåòñÿ êîíñòðóêòîð êîïèðîâàíèÿ.
    a.print();

    a = func(); // ïðèñâàèâàíèå - èñïîëüçóåòñÿ operator=.
    a.print();

    return 0;
}
//---------------------------------------------------------------------------

выдает
Constructor <0x0012ff88>
Copy by ref <0x0012ff84>
Value <0x0012ff84>: 1
Constructor <0x0012ff4c>
Copy by ref <0x0012ff80>
Destructor <0x0012ff4c>
Assign by ref <0x0012ff84>
Destructor <0x0012ff80>
Value <0x0012ff84>: 2
Destructor <0x0012ff84>
Destructor <0x0012ff88>




Код: (C++)
//---------------------------------------------------------------------------
#pragma hdrstop
//---------------------------------------------------------------------------

#include <stdio.h>
#include <assert.h>

class myclass
{
public:
    int x;

    ~myclass()
    {
        printf("Destructor (0x%08x)", (unsigned int)(void*)this);
        fgetc(stdin);
    }

    myclass(int x = 0) : x(x)
    {
        printf("Constructor (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass(myclass &s) : x(s.x)
    {
        printf("Copy by ref (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass& operator=(myclass &s)
    {
        assert(&s != this);

        x = s.x;
        printf("Assign by ref (0x%08x)\n", (unsigned int)(void*)this);
        return *this;
    }

    void print()
    {
        printf("Value (0x%08x): %d\n", (unsigned int)(void*)this, x);
    }
};

myclass func()
{
    myclass b(2);

    return b;
}

#pragma argsused
int main()
{
    myclass b(1);
    myclass a = b; // èíèöèàëèçàöèÿ - èñïîëüçóåòñÿ êîíñòðóêòîð êîïèðîâàíèÿ.
    a.print();

    a = *&func(); // ïðèñâàèâàíèå - èñïîëüçóåòñÿ operator=.
    a.print();

    return 0;
}
//---------------------------------------------------------------------------
без *& пишет
Код:
[C++ Error] Unit1.cpp(58): E2285 Could not find a match for 'myclass::operator =(myclass)'
выдает
Constructor <0x0012ff88>
Copy by ref <0x0012ff84>
Value <0x0012ff84>: 1
Constructor <0x0012ff4c>
Copy by ref <0x0012ff80>
Destructor <0x0012ff4c>
Assign by ref <0x0012ff84>
Destructor <0x0012ff80>
Value <0x0012ff84>: 2
Destructor <0x0012ff84>
Destructor <0x0012ff88>

#pragma... - создается компилятором в самом начале, я оставляю
русские крокозябры появляются только при копировании через буфер обмена ИЗ компилятора

* builder.JPG (41.8 Кб - загружено 1018 раз.)
« Последнее редактирование: 20-03-2011 18:33 от FeelUs » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 20-03-2011 18:34 » 

Борланд работает по какому-то своему стандарту. В настройках проекта можно переключить на ANSI, то тогда заголовки VCL не будут компилироваться.

FeelUs, нифига не понятно. Ты привел один и тот же код. Еще раз: пиши понятнее. Думаешь, охота ломать глаза и голову и искать, что же ты там сделал?
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
FeelUs
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 20-03-2011 18:41 » 

второй код отличается от первого тем, что в в операторе присваивания и в конструкторе копирования отсутствует const
если при использовании класса не добавить *& между присваиванием и вызовом ф-ции, пишет ошибку
если добавить - работает
#pragma мне кажется ни на что не влияет
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 21-03-2011 08:28 » 

Может кто-нибудь проверить на компиляторах MS?
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #8 : 21-03-2011 08:35 » 

В какой студии? Имеется 2003 - 2010.
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #9 : 21-03-2011 08:38 » 

Если не трудно, то в двух крайних Улыбаюсь Т.ч. точно быть уверенным, как MSVC работает.

Жень, код бери из моего поста №1.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #10 : 21-03-2011 08:44 » 

Может кто-нибудь проверить на компиляторах MS?
а что проверить ?

а так
myclass(const myclass &s)
myclass& operator=(const myclass &s)


Добавлено через 46 секунд:
в шестёрке нормально компилится, в остальных Джон проверит ))
« Последнее редактирование: 21-03-2011 08:45 от Алексей1153++ » Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 21-03-2011 08:52 » 

Не, Леш, вот это:

Код: (C++)
#include <stdio.h>
#include <assert.h>

class myclass
{
public:
    int x;

    ~myclass()
    {
        printf("Destructor (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass(int x = 0) : x(x)
    {
        printf("Constructor (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass(const myclass &s) : x(s.x)
    {
        printf("Copy by ref (0x%08x)\n", (unsigned int)(void*)this);
    }

    myclass& operator=(const myclass &s)
    {
        assert(&s != this);

        x = s.x;
        printf("Assign by ref (0x%08x)\n", (unsigned int)(void*)this);
        return *this;
    }

    void print()
    {
        printf("Value (0x%08x): %d\n", (unsigned int)(void*)this, x);
    }
};

myclass func()
{
    myclass b(2);

    return b;
}

int main()
{
    myclass b(1);
    myclass a = b; // инициализация - используется конструктор копирования.
    a.print();

    a = func(); // присваивание - используется operator=.
    a.print();

    return 0;
}

Нужно не только скомпилировать, но и выполнить, а результат сюда показать Улыбаюсь


Добавлено через 40 секунд:
BCB6 у меня показывает тоже самое, что у FeelUs получилось.


Добавлено через 1 минуту и 23 секунды:
Результат в первом посте получен на gcc 4.1.2.
« Последнее редактирование: 21-03-2011 08:55 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #12 : 21-03-2011 08:59 » 

VS6
Constructor (0x0012ff70)
Copy by ref (0x0012ff6c)
Value (0x0012ff6c): 1
Constructor (0x0012fef4)
Copy by ref (0x0012ff68)
Destructor (0x0012fef4)
Assign by ref (0x0012ff6c)
Destructor (0x0012ff68)
Value (0x0012ff6c): 2
Destructor (0x0012ff6c)
Destructor (0x0012ff70)
« Последнее редактирование: 21-03-2011 09:01 от Алексей1153++ » Записан

Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #13 : 21-03-2011 09:05 » 

VS 2010 Ultimate Win32 C++ Console Project

Constructor (0x002aff10)
Copy by ref (0x002aff04)
Value (0x002aff04): 1
Constructor (0x002afdf0)
Copy by ref (0x002afe2c)
Destructor (0x002afdf0)
Assign by ref (0x002aff04)
Destructor (0x002afe2c)
Value (0x002aff04): 2
Destructor (0x002aff04)
Destructor (0x002aff10)


VS 2003 Version 7.1.3088

Constructor (0x0012fe90)
Copy by ref (0x0012fe84)
Value (0x0012fe84): 1
Constructor (0x0012fd74)
Copy by ref (0x0012fdac)
Destructor (0x0012fd74)
Assign by ref (0x0012fe84)
Destructor (0x0012fdac)
Value (0x0012fe84): 2
Destructor (0x0012fe84)
Destructor (0x0012fe90)
« Последнее редактирование: 21-03-2011 09:12 от Джон » Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #14 : 21-03-2011 11:07 » 

Спасибо Улыбаюсь

Значит выходит, что gcc оптимизирует, а BCB и VC делает код с двойной работой.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
FeelUs
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 21-03-2011 16:30 » 

напомню и обобщу вопрос:
есть некоторый класс, назавем его tree - состоит из одного указателя и кучи ф-ций
, есть функция вида
Код:
f(tree &);
- в роли ее у меня выступает оператор присваивания и конструктор копирования
и есть функция вида
Код:
tree g();
- в  ней у меня создается дерево
и надо сделать так
Код:
f(g());
, но возникает ошибка, но можно сделать
Код:
f(*&g())
могу ли я быть уверен, что деструктор промежуточного объекта не вызовется до того, как над ним поработает f()?


Добавлено через 20 минут и 59 секунд:
информация для тех, кто захочет предложить альтернативный вариант
Код: (C++)
class TNode;
class Tree
{
    TNode *lp;
public:
    Tree(Tree &x)
    {
        lp=x.lp;
        x.lp=NULL;
    }
    Tree &operator=(Tree &x)
    {
        TNode *p=x.lp;
        x.lp=lp;
        lp=p;
    }
    ~Tree()
    {
        //удаление всех узлов (конечно если lp!=NULL)
        lp=NULL;
    }
//и куча других методов
};

Tree CreateTree()
{
    Tree x;
    //далее над x'ом удобнее работать как над локальной переменной
    return x;
}

использование
{
Tree x;

x=*&CreateTree();
}
« Последнее редактирование: 21-03-2011 16:50 от FeelUs » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #16 : 21-03-2011 17:24 » 

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

Можешь. Если в чем неуверен - читай документацию. И экспериментируй.
Следующий тест:

Код: (C++)
#include <stdio.h>
#include <assert.h>

class myclass
{
public:
    int x;

    ~myclass()
    {
        printf("0x%08x: destructor\n", (unsigned int)(void*)this);
    }

    myclass(int x = 0) : x(x)
    {
        printf("0x%08x: constructor\n", (unsigned int)(void*)this);
    }

    myclass(const myclass &s) : x(s.x)
    {
        printf("0x%08x: copy by ref\n", (unsigned int)(void*)this);
    }

    myclass& operator=(const myclass &s)
    {
        assert(&s != this);

        x = s.x;
        printf("0x%08x: assign by ref\n", (unsigned int)(void*)this);
        return *this;
    }

    void print()
    {
        printf("0x%08x: value: %d\n", (unsigned int)(void*)this, x);
    }
};

myclass func()
{
    myclass b(2);

    printf("0x%08x: func()\n", (unsigned int)(void*)&b);
    return b;
}

void func2(myclass s)
{
    printf("0x%08x: func2()\n", (unsigned int)(void*)&s);
    s.x = 3;
}

int main()
{
    myclass b(1);
    myclass a = b;
    a.print();

    a = func();
    a.print();

    func2(func());

    return 0;
}
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
FeelUs
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #17 : 21-03-2011 18:01 » 

Цитата
читай документацию
она в большинстве случаев нерусская. а у меня с нерусским ооочень плохо
я собственно и пишу универсальный парсер, чтобы с помощью него было легко и просто написать свой переводчик (которые существуют меня, видишь ли, не устраивают)

Цитата
экспериментируй
эксперименты показывают, что второй закон Ньютона выполняется, а где гарантия, что он не изменится через пару минут Ага

а как по стандарту с++ должно быть?
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #18 : 21-03-2011 18:18 » 

я собственно и пишу универсальный парсер, чтобы с помощью него было легко и просто написать свой переводчик

английского ? )
Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #19 : 21-03-2011 18:22 » 

Скомпилированный код не изменится точно.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Джон
просто
Администратор

de
Offline Offline
Пол: Мужской

« Ответ #20 : 22-03-2011 07:48 » 

эксперименты показывают, что второй закон Ньютона выполняется, а где гарантия, что он не изменится через пару минут Ага

За последние примерно 300 лет ещё ни разу не изменился. Так что через пару минут не изменится. Гарантирую. Да-да
Записан

Я вам что? Дурак? По выходным и праздникам на работе работать. По выходным и праздникам я работаю дома.
"Just because the language allows you to do something does not mean that it’s the correct thing to do." Trey Nash
"Physics is like sex: sure, it may give some practical results, but that's not why we do it." Richard P. Feynman
"All science is either physics or stamp collecting." Ernest Rutherford
"Wer will, findet Wege, wer nicht will, findet Gründe."
FeelUs
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #21 : 16-04-2011 16:36 » 

За последние примерно 300 лет ещё ни разу не изменился. Так что через пару минут не изменится. Гарантирую. Да-да
за 300 лет ни разу не изменился
и как из этого следует
что он не изменится через пару минут?
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #22 : 17-04-2011 17:40 » 

Интуиция подсказывает, и стандарт подтверждает, что временные объекты должны удаляться только при достижении конца выражения

Цитата
Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception.

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


Думаю, никто не может поручиться, что в один прекрасный момент какой-то компилятор почему-то не перестанет поддерживать стандарт (сам стандарт уже никуда деться не может, поскольку в силу работы над c++0x вряд ли кто-то станет делать новую правку в старом стандарте). Например, баги будут в компиляторе.

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

Даже если завтра время жизни временной переменной в C++ может почему-либо измениться - это не основание не писать код так, как нужно сегодня.  Всё равно при переходе на новый компилятор нужно будет код тестировать (можно заложить отдельный специальный тест, если боязно), ибо там наверняка навылезет каких-нибудь ещё граблей, связанных с вольным толкованием стандарта, и от этого уж точно нельзя подстраховаться. Ну, придётся пофиксить код, чтобы он там работал. Ну и что?
Записан
FeelUs
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #23 : 20-05-2011 04:43 » 

спасибо большое, Вад, что посмотрели стандарт, это нужно для того, чтобы знать на кого ругаться и материться, если что Отлично

спасибо также, Вад, что рассказали текущую ситуацию в языках программирования...
но именно это и должно нас подталкивать к поиску альтернативных вариантов, чтобы все было просто и красиво

начнем с того, что есть переменные и есть значения (помоему это называется l-value и r-value)(что это (значения) - для элементарных переменных - понимаем, для классов - сейчас выясним)
и константные ссылки можно инициализировать и константными переменными (получается ссылка на эту переменную) и значениями (тоже получается ссылка на хз какую переменную, инициализированную копи конструктором)
Улыбаюсь) а также есть const_cast<>(), который снимает константность

таким образом такой код работает
Код: (C++)
...
    Tree(const Tree &x)
    {
        lp=x.lp;
        const_cast<Tree &>(x).lp=NULL;
    }
    Tree &operator=(Tree &x)
    {
        TNode *p=x.lp;
        const_cast<Tree &>(x).lp=lp;
        lp=p;
    }
...
правда теперь нельзя создавать константные деревья, но если они мне понадобятся - напишу отдельный класс взаимодействующий с этим

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

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

опыты проводились над:
Код: (C++)
//---------------------------------------------------------------------------
#pragma hdrstop
//---------------------------------------------------------------------------

#include <stdio.h>
#include <assert.h>

class myclass
{
public:
    int x;

    ~myclass()
    {
        print("Destructor ");
        fgetc(stdin);
    }

    myclass(int x = 0) : x(x)
    {
        print("Constructor ");
    }

    myclass(myclass &s) : x(s.x)
    {
        const_cast<myclass &>(s).x=0;
        print("Copy constructor ");
        s.print("    from ");
    }

    myclass& operator=(myclass const &s)
    {
        assert(&s != this);

        x = s.x;
        const_cast<myclass &>(s).x=0;
        print("operator= ");
        s.print("    from ");
        return *this;
    }

    void print(char *str="")const
    {
        printf("%sValue (0x%08x): %d\n", str, (unsigned int)(void*)this, x);
    }
};

myclass func()
{
    printf("IN FUNCTION first\n");
    myclass b(2);

    printf("IN FUNCTION before return\n");
    return b;
}

#pragma argsused
int main()
{
    myclass b(1);
    myclass a = b; // èíèöèàëèçàöèÿ - èñïîëüçóåòñÿ êîíñòðóêòîð êîïèðîâàíèÿ.
    a.print();

    myclass c = func();   //myclass &c = func();
    printf("AFTER OPERATOR=\n");
    c.print();

    a =  func(); // ïðèñâàèâàíèå - èñïîëüçóåòñÿ operator=.
    printf("AFTER OPERATOR=\n");

    return 0;
}
//---------------------------------------------------------------------------
Сочиняю... в заключение хотелось бы опять все полученное интуицией и опытами подтвердить стандартом или мнением опытного программиста, что так и должно быть...
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #24 : 20-05-2011 04:57 » 

какой грустный код Жаль
const_cast это страшный зверь, при максимальных уровнях оптимизации поведение программы может быть не детерминированным
компилятор может вставлять кэширование const объектов и прочая хрень
используй mutable
оператор присваивания со свопом внутри это помоему, какая-то подстава для пользователя класса, сделайте метод swap

копирующий конструктор не вызвается ибо rvo/nrvo http://alenacpp.blogspot.com/2008/02/rvo-nrvo.html и прочий inline
Записан

Странно всё это....
PredatorAlpha
Помогающий

us
Offline Offline

« Ответ #25 : 24-05-2011 09:33 » 

спасибо большое, Вад, что посмотрели стандарт, это нужно для того, чтобы знать на кого ругаться и материться, если что Отлично
спасибо также, Вад, что рассказали текущую ситуацию в языках программирования...
но именно это и должно нас подталкивать к поиску альтернативных вариантов, чтобы все было просто и красиво
Звиняйте что лезу не в свой разговор, но это просто паранойя - не доверять решению, которое было запечатано в стандарте почти двадцать лет тому назад, и не менялось (в сторону уменьшения).
Если Вам интересно, как принималось это решение, какие аргументы приводились, из каких вариантов выбиралось - рекомендую книгу Стауструпа "Дизайн и эволюция C++", там в главе "6.3.2. Время жизни объектов" это подробно описано. С примерами, пояснениями.
Записан
FeelUs
Участник

ru
Offline Offline
Пол: Мужской

« Ответ #26 : 08-08-2011 21:02 » 

насколько я на данный момент понял, у объектов нет понятия rvalue и lvalue
но есть понятие временный объект - объект, возвращенный из функции по значению, или сконструированный прямо в выражении (разименованный указатель на объект - не является временным объектом)
а все дело было в том, что у борланда нельзя передавать
временные объекты
по неконстантным ссылкам
в конструкторы и операторы присваивания, а в другие функции, методы и операторы передавать так можно
скачал msvc2008, там это можно => все работает без const_cast'ов и mutabl'ов
PS оператор присваивания со свапом - действительно не то, сделал delete lp; lp=x.lp; x.lp=NULL;
Записан
PredatorAlpha
Помогающий

us
Offline Offline

« Ответ #27 : 11-08-2011 12:41 » 

Борланд - это отдельная история...
Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #28 : 12-08-2011 04:23 » 

Борланд - это отдельная история...
а при чём тут Борлад?
Записан

Странно всё это....
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines