LINUX.ORG.RU

[c++] wtf is &*this?

 


0

1

Хочется подтвердить уверенность в том, что конструкция &*this эквивалентна this.

На всякий случай контекст:

    /**
     * Returns const iterator for the first atom.
     */
    const_atom_iterator atom_begin () const {
        return const_atom_iterator (&*this, _atoms + atom_index_begin());
    }

    /**
     * Returns const iterator after the last atom.
     */
    const_atom_iterator atom_end () const {
        return const_atom_iterator (&*this, _atoms + atom_index_end());
    }

Перегрузка operator* и volatile явно не из этой оперы. Результат автоматического рефакторинга? Органическое повреждение мозга?


o__O

p.s.: (не в тему) в качестве аргумента функции применял такое ссылку на указатель, но там это оправдано было:

QDataStream &operator>> (QDataStream &in, qfgui::BoundaryCondition *&bc)
{
    // на случай, если мы что-то не смогли считать до этого (размер массива)
    if(in.status() != QDataStream::Ok) {
        throw false;
    }
    bc = new BoundaryCondition(in);
    // а это на случай, если мы что-то не смогли считать сейчас
    if(in.status() != QDataStream::Ok) {
        throw false;
    }
    return in;
}
Obey-Kun ★★★★★
()
Ответ на: комментарий от skwak

> так оно и без &* не падает

ес-но, проверялось именно &*this

aho
()
Ответ на: комментарий от sanuda

Скорее не обязан падать, undefined behavior.

Впрочем зачем может пригодиться этот &*this так и непонятно. И не было бы так любопытно, если бы эта шиза не с такой систематичностью использовалась в том коде, с которым приходится мне иметь дело.

skwak
() автор топика
;;return ((((((((&*&*&*&*&*&*&*&*&*&*&*&*&*this))))))));;;;;;
Obey-Kun ★★★★★
()
Ответ на: комментарий от proud_anon

> &*this is yet another reason for C++ to die.

из разряда:

/0 is yet another reason for C to die.

aho
()
Ответ на: комментарий от do0dlez

> смущает, и?Что ЭТО делает?

вычисляет смещение поля структуры

как у нулл может быть member?


так же как this может быть NULL - это основы С и С++, любители более «продвинутых» языков этого не понимают - потому и считают чем-то плохим, т.к. их языки устроены по-другому

aho
()
Ответ на: комментарий от do0dlez

> как у нулл может быть member?

Молча. Адресная арифметика, только и всего. Никогда не стоит забывать, что Си — в достаточной мере низкоуровневый язык, ну а Си++ не далеко от него ушел.

geekless ★★
()
Ответ на: комментарий от do0dlez

а как this может быть NULL

class A {
  A* foo(void) {
    return this;
  }
}

void baz(A* a) {
  A* b = a->foo();
}

Чему будет равен b в функции baz (и this в методе A::foo), когда кто-то в дебрях кода по ошибке вызовет baz(NULL) ?

geekless ★★
()
Ответ на: комментарий от aho

>а подобное в С вас не смущает:
>#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

Когда мы понимаем, что «тип» в C - это, на самом деле, полная условность, своего рода карта смещений, позволяющая быстро ориентироваться внутри блока памяти, это не смущает.

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

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

proud_anon ★★★★★
()
Ответ на: комментарий от proud_anon

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

да, когда «оказывается» - это плохо

aho
()
Ответ на: комментарий от proud_anon

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

amomymous ★★★
()
Ответ на: комментарий от skwak

> Скорее не обязан падать, undefined behavior.

Это еще почему?! Вполне себе справедливая и соответствующая стандарту конструкция. this не отличается ничем от указателя другого любого типа.

anonymous
()

&*this немного глупая конструкция ибо эквивалент обычного зиса $ cat test.cpp

#include <stdio.h>

class A
{
    public:
        size_t foo();
        size_t bar();
};

size_t A::foo()
{
    return (size_t)&*this;
}

size_t A::bar()
{
    return (size_t)this;
}

int main(int argc, char **argv)
{
    A a;
    printf("a.foo(): 0x%x\n", a.foo());
    printf("a.bar(): 0x%x\n", a.bar());
    printf("a      : 0x%x\n", &a);

    return 0;
}
$ ./a.out 
a.foo(): 0x31f1434f
a.bar(): 0x31f1434f
a      : 0x31f1434f

anonymous
()
Ответ на: комментарий от aho

а подобное в С вас не смущает

Не смущает, но после C# полезно было вспомнить. Спасибо.

gizzka ★★
()
Ответ на: комментарий от const86

> А перегрузка operator&()?

Не, молчит греп. Инфа 100%.

skwak
() автор топика
Ответ на: комментарий от anonymous

И машинный код для обоих вариантов одинаковый.

skwak
() автор топика
Ответ на: комментарий от do0dlez

из .text секции. просто этому методу передаётся 0 вместо this. Всё работает до тех пор, пока метод не сделает this->... что аналогично к обращению к любому не статичному полю класса. Вот тогда и segfault будет.

Именно по-этому статические методы можно использовать не имея экземпляра. Им этот this просто не передёт никто. И именно по этому они не могут обратится к обычным (не статическим) полям класса. У них этого this'a нету.

nanoo_linux
()

если * and & не перегружены, то ничего не будет. Если перегружены - привет.

Хотя мотивы автора не совсем понятны. Кастую namezys в тред.

nanoo_linux
()
Ответ на: комментарий от nanoo_linux

А, и если такие пироги, то перегруженный operator* можно только у *this позвать. У this не получится.

skwak
() автор топика
Ответ на: комментарий от jtootf

> смущает: это UB, потому нормальные компиляторы определяют встроенный offsetof

да - оно есть в stddef.h, но некоторые( visual, tcc и т.д. ) компиляторы до сих определяют его через аналогичный макрос

aho
()

> &*this

это просто подсказка компилятору, что здесь поинтер this не нулевой. например, если есть код

&*this; if (this) { xxxx; }

то компилятор сообразит, что this ненулевой и опустит проверку this на NULL перед xxxx;

anonymous
()
Ответ на: комментарий от nanoo_linux

Ситуация с перегрузкой операторов понятна - рассматривать ее не будем.

Попробуем Расмотреть только операторы по умолчанию. * фактически возвращает ссылку. О реализации ссылок не слова не говорится. Обычно, это тот жесамый указатель с сахаром (ну еще мелочь типа отложенной смерти временного объекта). На x86 нет не каких специальных правил обработки указателя. Но компилятор вполне может расчитывать, что там лежит валидный объект. И, возможна рахитектура, на которой такая работа может вызывать падение. Но это скорейиз области фантастики. Операция взятия адреса тут тоже «синтаксический сахар».

Вообще разыменование невалидной ссылки (по которой не лежит объект указанного типа) ошибочная операция. Для примера классика: взятие инта из char* буфера на архитектурах, учитывающих выравнивание типа. Но, опять же, это проявится при действии. А тут у нас синтаксический сахар.

Подэтожу: * компилятор тупо оптимизирует * развернет синтаксический сахар. Тут возможно падение на фантастический архитектуре, но я такой архитектуры не знаю

namezys ★★★★
()
Ответ на: комментарий от namezys

Вообще на практике такой код не упадет некогда. Ну разве на чем нибудь очень умном, как эльбрус

namezys ★★★★
()
Ответ на: комментарий от nanoo_linux

> Всё работает до тех пор, пока метод не сделает разыменование this чтобы обратиться к переменной-члену или виртуальному методу.

fixed

geekless ★★
()
Ответ на: комментарий от jtootf

> смущает: это UB, потому нормальные компиляторы определяют встроенный offsetof

Это с точки зрения прикладной программы UB. А с точки зрения компилятора, UB превращается во вполне defined behavior. Поэтому если разработчики компилятора знают, что делают, то и могут использовать такие фичи.

geekless ★★
()
Ответ на: комментарий от aho

что оно делает я догадался, просто смутило обращение к полю *(NULL).

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

  • представляем, что у нас в NULL есть нужная структура;
  • вычисляем адрес поля
  • т.к. адрес этого поля вычислялся, считая, что структура начинается в 0, то таким образом мы получаем смещение поля

да?

do0dlez ★★
()
Ответ на: комментарий от roof

С какого-то this == 0? Внутри использующего его метода он всегда не равен нулю, если только не сделали delete this перед этим.

anonymous
()
Ответ на: комментарий от anonymous

> С какого-то this == 0? Внутри использующего его метода он всегда не равен нулю, если только не сделали delete this перед этим.

во-первых совсем не всегда, во-вторых delete this - этот самый this никоим образом не меняет

aho
()
Ответ на: комментарий от anonymous

С такого, что метод, не использующий члены-переменные, можно вызвать даже не вызывая new, что выше по топику успешно продемонстрировали.

roof ★★
()
Ответ на: комментарий от anonymous

ты джавист штоле? this - это указатель, а указатель может указывать на что угодно. Если действительно джавист - добро пожаловать в ад c++!

nanoo_linux
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.