Грокаем C++
8.37K subscribers
34 photos
1 video
3 files
459 links
Два сеньора C++ - Владимир и Денис - отныне ваши гиды в этом дремучем мире плюсов.

По всем вопросам - @ninjatelegramm

Менеджер: @Spiral_Yuri
Реклама: https://telega.in/c/grokaemcpp
Мы на TGstat: https://tgstat.ru/channel/@grokaemcpp/stat
Download Telegram
Addressof
#опытным

Говорят вот, что питон - такой легкий для входа в него язык. Его код можно читать, как английские английский текст. А вот С/С++ хаят за его несколько отталкивающую внешность. Чего только указатели стоят...

Кстати о них. Все мы знаем, как получить адрес объекта:

int number = 42;
int * p_num = &number;


Человек, ни разу не видевший код на плюсах, увидит здесь какие-то магические символы. Вроде число, а вроде какие-то руны * и &. Но плюсы тоже могут в читаемость! Причем именно в аспекте адресов.

Вместо непонятного новичкам амперсанда есть функция std::addressof! Она шаблонная, позволяет получить реальный адрес непосредственно самого объекта и доступна с С++11. Для нее кстати удалена перегрузка с const T&&

template< class T >
T* addressof( T& arg ) noexcept;

template< class T >
const T* addressof( const T&& ) = delete;


Это делает функцию еще одним примером использования константной правой ссылки .

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

А вот теперь мы возвращаемся к предыдущему посту про перегрузку оператора взятия адреса. Так как его можно перегружать, то мы можем возвращать вообще любой адрес, который потенциально никак не связан с самим объектом. В этом случае не очень понятно, как взять трушный адрес объекта. Как раз таки std::addressof - способ получить валидный адрес непосредственно самого объекта.

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

А с С++17 она еще и констэкспр, это для любителей компайл-тайма.

Вот вам примерчик:

template<class T>
struct Ptr
{
T* pad; // add pad to show difference between 'this' and 'data'
T* data;
Ptr(T* arg) : pad(nullptr), data(arg)
{
std::cout << "Ctor this = " << this << '\n';
}
 
~Ptr() { delete data; }
T** operator&() { return &data; }
};
 
template<class T>
void f(Ptr<T>* p)
{
std::cout << "Ptr overload called with p = " << p << '\n';
}
 
void f(int** p)
{
std::cout << "int** overload called with p = " << p << '\n';
}
 
int main()
{
Ptr<int> p(new int(42));
f(&p); // calls int** overload
f(std::addressof(p)); // calls Ptr<int>* overload, (= this)
}

// OUTPUT
// Ctor this = 0x7fff59ae6e88
// int** overload called with p = 0x7fff59ae6e90
// Ptr overload called with p = 0x7fff59ae6e88


Здесь какие-то злые персоналии перегрузили оператор взятия адреса у класса Ptr так, чтобы он возвращал указатель на одно из его полей. Ну и потом сравнивают результат работы оператора с результатом выполнения функции std::addressof.

Видно, что трушный адрес объекта, полученный с помощью this и адрес, возвращенный из std::addressof полностью совпадают. А перегруженный оператор возвращает другое значение.

Express your thoughts clearly. Stay cool.

#cpp #cpp11 #cpp17