2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 Распределитель памяти (С++)
Сообщение26.05.2011, 09:14 
Аватара пользователя


22/01/11
23
Сидней
Объясните пожалуйста, что здесь происходит и как это работает:

Используется синтаксис C++
ret = new( &m_ddd ) SetLinear( static_cast< dLevel >( averageD() ) );
 


Спасибо!

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 13:30 


03/07/09
9
Странная конструкция.
Тут для объекта "m_ddd" вызывается конструктор "SetLinear" с соответствующим параметром, а затем его адрес возвращается и записывается в переменную "ret".

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 16:05 
Заслуженный участник


04/05/09
4587
Это вызов оператора new с параметром &m_ddd:
Используется синтаксис C++
void* ptr = operator new(sizeof(SetLinear), &m_add);

вместо стандартного:
Используется синтаксис C++
void* ptr = operator new(sizeof(SetLinear));


А потом в выделенной памяти компилятор как обычно вызовет конструктор класса SetLinear с параметром static_cast< dLevel >( averageD() ).

(исправил)

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 16:37 
Заслуженный участник


09/08/09
3438
С.Петербург
venco в сообщении #450431 писал(а):
Это вызов оператора new с параметром &m_ddd:
Используется синтаксис C++
void* ptr = operator new(&m_add, sizeof(SetLinear));
А разве не
Используется синтаксис C++
void* ptr = operator new(sizeof(SetLinear), &m_add);
?

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 16:39 
Заслуженный участник


04/05/09
4587
Вы правы, перепутал.

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 17:47 
Заслуженный участник


26/07/09
1559
Алматы
2usr00210
Цитата:
Объясните пожалуйста, что здесь происходит и как это работает

Здесь у вас оператору new передается дополнительный параметр, который в норме позволяет разместить создаваемый вами объект ни где-нибудь в куче, а в указанном с помощью этого лишнего параметра месте (т.н. placement syntax). В вашем случае, новый объект класса SetLinear будет размещен по адресу &m_ddd. То есть у вас есть возможность выделить память заранее, не полагаясь на внутренние механизмы run-time библиотеки. Даже не знаю, в каких ситуациях это даст хоть какие-то преимущества... Ну разве что во встраиваемых системах...

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 19:16 


03/07/09
9
venco в сообщении #450431 писал(а):
Это вызов оператора new с параметром &m_ddd:
Используется синтаксис C++
void* ptr = operator new(sizeof(SetLinear), &m_add);

вместо стандартного:
Используется синтаксис C++
void* ptr = operator new(sizeof(SetLinear));


А потом в выделенной памяти компилятор как обычно вызовет конструктор класса SetLinear с параметром static_cast< dLevel >( averageD() ).

(исправил)


Память здесь не выделяется, только вызывается конструктор того объекта, адрес которого передан в качестве параметра. И этот же адрес потом и возвращается.
Запустите вот эту программу и посмотрите: два раза вызывается конструктор одного и того же объекта, а при попытке освободить память возникает ошибка.
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#include <iostream>

struct test
{
    test ()
    {
        std::cout << "test(): " << this << std::endl;
    }
   
    ~test ()
    {
        std::cout << "~test(): " << this << std::endl;
    }
};
 
int main()
{
    test t;
    test * tt = new (&t) test;
   
    delete tt;
   
    return 0;
}

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 20:20 
Заслуженный участник


04/05/09
4587
volovzi в сообщении #450503 писал(а):
Память здесь не выделяется, только вызывается конструктор того объекта, адрес которого передан в качестве параметра. И этот же адрес потом и возвращается.
Это потому, что стандартной библиотекой определено только два варианта оператора new (ну и ещё два с nothrow):
Используется синтаксис C++
void* operator new(size_t);
void* operator new(size_t, void*);

Первый вариант, без дополнительных параметров, вызывает malloc().
Второй возвращает свой второй аргумент без изменений.
Именно второй вариант подходит под ваш вызов, и в результате просто вызывается конструктор по указанному адресу.
Если же в программе есть ещё варианты оператора new, то вызовется тот, что больше подходит к аргументам, как и с обычной перегруженной функцией. И этот оператор может делать нетривиальные вещи, типа выделения памяти в shared memory.

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 21:12 


03/07/09
9
venco в сообщении #450528 писал(а):
Если же в программе есть ещё варианты оператора new, то вызовется тот, что больше подходит к аргументам, как и с обычной перегруженной функцией. И этот оператор может делать нетривиальные вещи, типа выделения памяти в shared memory.

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

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение27.05.2011, 00:44 
Заслуженный участник


26/07/09
1559
Алматы
2volovzi
Цитата:
только вызывается конструктор того объекта, адрес которого передан в качестве параметра
...
два раза вызывается конструктор одного и того же объекта, а при попытке освободить память возникает ошибка

Кажется, вы не правы. Как я уже сказал, такой синтаксис используется для размещения объектов в заранее приготовленной памяти. В вашем примере вместо test t может быть любой другой объект достаточного размера (например, char p[1000] :) ) и именно его адрес вы можете передавать в качестве параметра оператору new. Кстати, первый вызов конструктора выполняется именно за счет объявления test t, второй -- за счет оператора new (это можно проверить вставив между соответствующими строчками отладочную печать).

Эта ситуация интересна тем, что вообще-то удалять таким образом созданный объект вы должны очень аккуратно. Во-первых, delete (стандартный) использовать нельзя (ошибку вы видели). Это тот случай, когда в C++ пригождается возможность явного вызова деструктора -- вместо delete tt надо писать tt->test::~test(), или tt->~test(), если нужен виртуальный вызов.

Конкретно в вашем случае, есть дополнительная опасность автоматического вызова деструктора для объекта t, который уже фактически был уничтожен.

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение27.05.2011, 00:57 
Аватара пользователя


22/01/11
23
Сидней
огромное всем спасибо за разъяснения! теперь кое-что понятно :D

но кое-что теперь хочется уточнить.
Скажите пожалуйста, Circiter, почему вы сказали, что "Даже не знаю, в каких ситуациях это даст хоть какие-то преимущества"? Вы попали в точку, предположив использование такой конструкции в эмбеддед системах, именно в таком контексте я ее и встретил. Но мне не совсем понятны причины ваших сомнений относительно преимуществ такого подхода вообще.

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение27.05.2011, 01:53 
Заслуженный участник


26/07/09
1559
Алматы
2usr00210
Просто оператор new у меня намертво ассоциируется с динамическим выделением памяти (само слово "new" намекает на создание нового объекта), а тут получается что-то статическое, равносильное явному вызову конструктора... Преимущественно отсюда-то и сомнения... Ну а встраиваемые системы вспомнились из-за некоторой низкоуровневости такого варианта new, с одной стороны позволяющей лучше конролировать ситуацию, например в условиях ограниченности ресурсов, с другой -- потенциально способной привести к каким-нибудь негативным последствиям, как это часто бывает когда программисты пытаются делать что-то "за компилятор/среду". :)

То есть, это именно всего-лишь сомнения, а не возражения по-существу. Более того, placement new используется довольно широко; например, если я не ошибаюсь, все реализации std::vector используют нечто подобное. Но у меня вообще никогда необходимость в таком подходе не возникала...

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение27.05.2011, 02:09 
Аватара пользователя


22/01/11
23
Сидней
все понятно, спасибо!

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение27.05.2011, 11:32 


03/07/09
9
Circiter в сообщении #450621 писал(а):
Кажется, вы не правы. Как я уже сказал, такой синтаксис используется для размещения объектов в заранее приготовленной памяти. В вашем примере вместо test t может быть любой другой объект достаточного размера (например, char p[1000] :) ) и именно его адрес вы можете передавать в качестве параметра оператору new.

Прекрасно, напишем вот так :)
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#include <iostream>

struct test
{
    test ()
    {
        std::cout << "test(): " << this << std::endl;
    }
   
    ~test ()
    {
        std::cout << "~test(): " << this << std::endl;
    }
};

int main()
{
    char p[sizeof(test)];
    test * t = new (&p) test;

    delete t;
   
    return 0;
}


Да, я ошибся в формулировке: надо было написать не "вызывается конструктор объекта по адресу", а "конструируется объект и записывается по адресу". В остальном всё верно: вызывается конструктор без выделения новой памяти, что и демонстрирует мой пример.

Цитата:
Кстати, первый вызов конструктора выполняется именно за счет объявления test t, второй -- за счет оператора new (это можно проверить вставив между соответствующими строчками отладочную печать).

Эта ситуация интересна тем, что вообще-то удалять таким образом созданный объект вы должны очень аккуратно. Во-первых, delete (стандартный) использовать нельзя (ошибку вы видели). Это тот случай, когда в C++ пригождается возможность явного вызова деструктора -- вместо delete tt надо писать tt->test::~test(), или tt->~test(), если нужен виртуальный вызов.

Конкретно в вашем случае, есть дополнительная опасность автоматического вызова деструктора для объекта t, который уже фактически был уничтожен.

Именно для того, чтобы проиллюстрировать вышесказанное, я и составил пример именно так. Я думал, это понятно :) .

 Профиль  
                  
 
 Re: Распределитель памяти (С++)
Сообщение28.05.2011, 00:48 
Заслуженный участник


26/07/09
1559
Алматы
2volovzi
Ну тогда извините, мне показалось. Будем считать, что я это топикстартеру писал. :)

Кстати, в последнем (новом) вашем примере там точно амперсанд не лишний? Такое ощущение, будто бы вы пытаетесь ваш объект в 4 байта запихнуть. :)

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 17 ]  На страницу 1, 2  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group