2014 dxdy logo

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

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




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

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


Спасибо!

 
 
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 13:30 
Странная конструкция.
Тут для объекта "m_ddd" вызывается конструктор "SetLinear" с соответствующим параметром, а затем его адрес возвращается и записывается в переменную "ret".

 
 
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 16:05 
Это вызов оператора 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 
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 
Вы правы, перепутал.

 
 
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 17:47 
2usr00210
Цитата:
Объясните пожалуйста, что здесь происходит и как это работает

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

 
 
 
 Re: Распределитель памяти (С++)
Сообщение26.05.2011, 19:16 
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 
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 
venco в сообщении #450528 писал(а):
Если же в программе есть ещё варианты оператора new, то вызовется тот, что больше подходит к аргументам, как и с обычной перегруженной функцией. И этот оператор может делать нетривиальные вещи, типа выделения памяти в shared memory.

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

 
 
 
 Re: Распределитель памяти (С++)
Сообщение27.05.2011, 00:44 
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 
Аватара пользователя
огромное всем спасибо за разъяснения! теперь кое-что понятно :D

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

 
 
 
 Re: Распределитель памяти (С++)
Сообщение27.05.2011, 01:53 
2usr00210
Просто оператор new у меня намертво ассоциируется с динамическим выделением памяти (само слово "new" намекает на создание нового объекта), а тут получается что-то статическое, равносильное явному вызову конструктора... Преимущественно отсюда-то и сомнения... Ну а встраиваемые системы вспомнились из-за некоторой низкоуровневости такого варианта new, с одной стороны позволяющей лучше конролировать ситуацию, например в условиях ограниченности ресурсов, с другой -- потенциально способной привести к каким-нибудь негативным последствиям, как это часто бывает когда программисты пытаются делать что-то "за компилятор/среду". :)

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

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

 
 
 
 Re: Распределитель памяти (С++)
Сообщение27.05.2011, 11:32 
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 
2volovzi
Ну тогда извините, мне показалось. Будем считать, что я это топикстартеру писал. :)

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

 
 
 [ Сообщений: 17 ]  На страницу 1, 2  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group