Я храню объекты в буфере. ... Если я знаю общий размер объекта, допустимо ли создать указатель на эту память и вызвать для нее функции?
Это приемлемо в той степени, в которой допустимо использование приведений:
#include <iostream>
namespace {
class A {
int i;
int j;
public:
int value()
{
return i + j;
}
};
}
int main()
{
char buffer[] = { 1, 2 };
std::cout << reinterpret_cast<A*>(buffer)->value() << '\n';
}
Преобразование объекта в нечто вроде необработанной памяти и обратно на самом деле довольно распространено, особенно в мире Си. Однако, если вы используете иерархию классов, имеет смысл использовать указатель на функции-члены.
скажи, что у меня есть следующий класс: ...
если я знаю, что этот класс имеет размер 24, и я знаю адрес, где он начинается в памяти ...
Здесь все становится сложнее. Размер объекта включает в себя размер его элементов данных (и любых элементов данных из любых базовых классов) плюс любые отступы плюс любые указатели функций или информацию, зависящую от реализации, за вычетом чего-либо, сохраненного из определенных оптимизаций размера (пустая оптимизация базового класса). Если полученное число равно 0 байтов, то объект должен занимать как минимум один байт в памяти. Эти вещи представляют собой сочетание языковых проблем и общих требований, предъявляемых большинством процессоров к доступу к памяти. Попытка заставить вещи работать должным образом может быть настоящей болью .
Если вы просто выделите объект и приведете к исходной памяти и из нее, вы можете игнорировать эти проблемы. Но если вы копируете внутренности объекта в какой-то буфер, то они довольно быстро поднимают голову. Приведенный выше код опирается на несколько общих правил выравнивания (т. Е. Я знаю, что класс A будет иметь те же ограничения на выравнивание, что и целые, и, таким образом, массив может быть безопасно приведен к A; но я не мог обязательно гарантировать то же самое, если бы я приводил части массива к A и части к другим классам с другими членами данных).
Да, и при копировании объектов вам нужно убедиться, что вы правильно обрабатываете указатели.
Вас также могут заинтересовать такие вещи, как Буферы протокола Google или Экономия Facebook .
Да, эти проблемы сложны. И, да, некоторые языки программирования скрывают их. Но под ковер попадает огромное количество вещей :
В Sun HotSpot JVM хранилище объектов выравнивается по ближайшей 64-битной границе. Кроме того, каждый объект имеет в памяти заголовок из двух слов. Размер слова в JVM обычно соответствует собственному размеру указателя платформы. (Для объекта, состоящего только из 32-разрядного типа int и 64-разрядного двойного числа - 96 бит данных - потребуется) два слова для заголовка объекта, одно слово для целого числа, два слова для двойного. Это 5 слов: 160 бит. Из-за выравнивания этот объект будет занимать 192 бита памяти.
Это связано с тем, что Sun полагается на относительно простую тактику решения проблем с выравниванием памяти (на воображаемом процессоре символу может быть разрешено существовать в любом месте памяти, int в любом месте, кратном 4, и двойной может потребоваться выделять только области памяти, которые делятся на 32, но наиболее ограничительное требование выравнивания также удовлетворяет всем остальным требованиям выравнивания, поэтому Sun выравнивает все в соответствии с наиболее ограничивающим местоположением).
Другая тактика выравнивания памяти может вернуть часть этого пространства .