Впал в ступор увидев такое
От: Lanjeron32  
Дата: 16.03.19 07:29
Оценка:
Всем привет. В одном из блогов мне встретилось такое объявление:

struct str {
template<bool B> str() {}
};
extern str a;

Далее автор предлагает "написать определение переменной a".
Re: Впал в ступор увидев такое
От: Croessmah  
Дата: 16.03.19 08:16
Оценка:
Здравствуйте, Lanjeron32, Вы писали:

L>Далее автор предлагает "написать определение переменной a".


str a(a);
Re: Впал в ступор увидев такое
От: rg45 СССР  
Дата: 16.03.19 08:22
Оценка: 2 (1)
Здравствуйте, Lanjeron32, Вы писали:

L>
L>struct str {
L>template<bool B> str() {}
L>};
L>extern str a;
L>

L>Далее автор предлагает "написать определение переменной a".

Он же не требует использовать при этом именно этот конкретный конструктор — который недоступен для использования, согласно стандарту. Но можно воспользоваться другими конструторами — копирования и перемещения, которые определены неявно компилятором.

Не уверен на счет корректности автоинициализации, как здесь
Автор: Croessmah
Дата: 16.03.19
, но, до тех пор, пока класс остается POD-типом, можно интерпретировать любой кусок памяти, достаточного размера, как объект данного типа и выполнить инициализацию копированием:

template <typename T>
using storage = std::array<unsigned char, sizeof(T)>;

str a = reinterpret_cast<const str&>(static_cast<const storage<str>&>(storage<str>()));
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 16.03.2019 11:11 rg45 . Предыдущая версия . Еще …
Отредактировано 16.03.2019 11:07 rg45 . Предыдущая версия .
Re[2]: Впал в ступор увидев такое
От: Croessmah  
Дата: 16.03.19 13:12
Оценка:
Здравствуйте, rg45, Вы писали:

R>Не уверен на счет корректности автоинициализации, как здесь
Автор: Croessmah
Дата: 16.03.19


А что Вас смущает? Объект занят самокопированием. Синтаксически здесь всё корректно.

6.3.2 Point of declaration
1. The point of declaration for a name is immediately after its complete declarator (Clause 11) and before its
initializer (if any), except as noted below. [ Example:

unsigned char x = 12;
{ unsigned char x = x; }


Here the second x is initialized with its own (indeterminate) value. —end example ]

Отредактировано 16.03.2019 13:13 Croessmah . Предыдущая версия .
Re[3]: Впал в ступор увидев такое
От: rg45 СССР  
Дата: 16.03.19 14:04
Оценка:
Здравствуйте, Croessmah, Вы писали:

C>А что Вас смущает? Объект занят самокопированием. Синтаксически здесь всё корректно.


Не знаю, не готов отстаивать свою позицию. Просто это рвет мои шаблоны. Как мне казалось, принимая ссылку на самого себя, конструктор копирования пытается использовать объект, время жизни которого еще не началось (время жизни объекта начинается после завершения работы конструктора, согласно стандарту). Я попробовал смоделировать ситуацию, когда это привело бы к каким-нибудь неприятностям. Но не тут-то было. Попробовал и так, и эдак — работает и не падает! Мне нужен таймаут, чтобы раобраться получше.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Впал в ступор увидев такое
От: Croessmah  
Дата: 16.03.19 14:23
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Croessmah, Вы писали:


C>>А что Вас смущает? Объект занят самокопированием. Синтаксически здесь всё корректно.


R>конструктор копирования пытается использовать объект, время жизни которого еще не началось (время жизни объекта начинается после завершения работы конструктора, согласно стандарту).


Тоже самое происходит и в Вашем коде. У Вас есть только буфер байт, в нем нет объекта типа str, т.е. Ваш код занимается тем же самым — копированием из объекта, время жизни которого еще не началось.

> Я попробовал смоделировать ситуацию, когда это привело бы к каким-нибудь неприятностям. Но не тут-то было. Попробовал и так, и эдак — работает и не падает!


Тип же не содержит каких-то сложных операций при конструировании.
Результат для типа, содержащего std::string есть здесь.
Может не воспроизводится, т.к. код содержит неопределенное поведение.
Re[3]: Впал в ступор увидев такое
От: rg45 СССР  
Дата: 16.03.19 14:36
Оценка:
Здравствуйте, Croessmah, Вы писали:

C>А что Вас смущает? Объект занят самокопированием. Синтаксически здесь всё корректно.


Если такая вот авто-инициализация разрешена, причем, не только для POD типов, тогда вся инкапсуляция, всякое сокрытие данных, идиомы pImpl — все накрывается медным тазом, ибо защитить инкапсулированные данные становится просто невозможно:

class A
{
public:

  A() : p(std::make_shared<int>()) {}

  int value() const { return *p; }
  void set_value(int value) { *p = value; }

private:
   std::shared_ptr<int> p;
};


Казалось бы, указатель надежно инкапсулирован. Но стоит только написать "A a(a)" и все обрушилось:

https://ideone.com/SFzTqs

Нет, не может быть, чтобы это было разрешенным способом инициализации для не POD-типов!
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[5]: Впал в ступор увидев такое
От: rg45 СССР  
Дата: 16.03.19 14:40
Оценка:
Здравствуйте, Croessmah, Вы писали:

C>Тоже самое происходит и в Вашем коде. У Вас есть только буфер байт, в нем нет объекта типа str, т.е. Ваш код занимается тем же самым — копированием из объекта, время жизни которого еще не началось.


Не то, что не началось, а никогда и не начиналось, потому что это просто кусок памяти. Для POD-типов это нормально, я же специально сделал на этом акцент.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Впал в ступор увидев такое
От: Croessmah  
Дата: 16.03.19 15:01
Оценка:
Здравствуйте, rg45, Вы писали:

R>ибо защитить инкапсулированные данные становится просто невозможно:


Вы можете в конструкторе копирования сравнить this с адресом переданного объекта, как это обычно делают в операторе присваивания.


A(A const & src): p((error_if_this(src), src.p)) {
}

void error_if_this(A const & src)
{
    assert(this != &src);
}



R> Нет, не может быть, чтобы это было разрешенным способом инициализации для не POD-типов!


Дело в доступности самого имени в этом контексте, а не том является ли тип POD'ом. У компилятора нет физической способности проверить передаете Вы в конструктор копирования этот же объект или какой-то другой:

A const & at(A const *);
//...
A a(at(&a));//Неизвестно вернет at ссылку на a или на другой объект
Отредактировано 16.03.2019 15:02 Croessmah . Предыдущая версия .
Re[5]: Впал в ступор увидев такое
От: rg45 СССР  
Дата: 16.03.19 15:15
Оценка:
Здравствуйте, Croessmah, Вы писали:

C>Вы можете в конструкторе копирования сравнить this с адресом переданного объекта, как это обычно делают в операторе присваивания.


То есть явно всегда писать конструкторы копирования только для того, чтобы проверить на this? Ну это вообще уже жесть какая-то.

C>Дело в доступности самого имени в этом контексте, а не том является ли тип POD'ом. У компилятора нет физической способности проверить передаете Вы в конструктор копирования этот же объект или какой-то другой:


Ты продолжаешь доказывать, что синтаксически все правильно. Так с этим никто и не спорил. UB потому и существует в природе, что комилятор не способен его задетектить. И ответственнось в этом случае на программисте, а не на компиляторе.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: Впал в ступор увидев такое
От: Croessmah  
Дата: 16.03.19 15:17
Оценка:
Здравствуйте, rg45, Вы писали:


R> Для POD-типов это нормально, я же специально сделал на этом акцент.


Не совсем так: https://en.cppreference.com/w/cpp/language/default_constructor#Trivial_default_constructor

A trivial default constructor is a constructor that performs no action. All data types compatible with the C language (POD types) are trivially default-constructible. Unlike in C, however, objects with trivial default constructors cannot be created by simply reinterpreting suitably aligned storage, such as memory allocated with std::malloc: placement-new is required to formally introduce a new object and avoid potential undefined behavior.

Re[6]: Впал в ступор увидев такое
От: Croessmah  
Дата: 16.03.19 15:34
Оценка:
Здравствуйте, rg45, Вы писали:

R>Ты продолжаешь доказывать, что синтаксически все правильно. Так с этим никто и не спорил. UB потому и существует в природе, что комилятор не способен его задетектить. И ответственнось в этом случае на программисте, а не на компиляторе.


Я не об этом пытаюсь сказать. Я предположил,что Вы сомневаетесь в правильности синтаксиса. Поэтому и спросил, уж не синтаксис ли Вас смущает, раз есть сомнения в корректности кода, ведь Вы же тоже привели код с UB (кстати, в нем лучше использовать std::aligned_storage вместо std::array, т.к можно будет указать правильное выравнивание).
Отредактировано 16.03.2019 15:37 Croessmah . Предыдущая версия .
Re[7]: Впал в ступор увидев такое
От: rg45 СССР  
Дата: 16.03.19 15:50
Оценка:
Здравствуйте, Croessmah, Вы писали:

R>>Ты продолжаешь доказывать, что синтаксически все правильно. Так с этим никто и не спорил. UB потому и существует в природе, что комилятор не способен его задетектить. И ответственнось в этом случае на программисте, а не на компиляторе.


C>Я не об этом пытаюсь сказать. Я предположил,что Вы сомневаетесь в правильности синтаксиса. Поэтому и спросил, уж не синтаксис ли Вас смущает, раз есть сомнения в корректности кода, ведь Вы же тоже привели код с UB (кстати, в нем лучше использовать std::aligned_storage вместо std::array, т.к можно будет указать правильное выравнивание).


Нет-нет, значит, я не очень удачно выразился, синтаксис вопросов не вызывал. Интересовала лишь корректность с точки зрения UB.

То есть, UB, все-таки, правильно я понимаю? Для всех типов, или только для non-POD? И как это обосновать с точки зрения стандарта, чтоб уже расставить все точки над "i" — "Object LIfetime", или еще как-то?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Впал в ступор увидев такое
От: σ  
Дата: 16.03.19 18:52
Оценка: 6 (1)
R>пока класс остается POD-типом, можно интерпретировать любой кусок памяти, достаточного размера, как объект данного типа

Вроде https://wg21.link/P0593 ещё не приняли (хотя одобрили)
Re: Впал в ступор увидев такое
От: B0FEE664  
Дата: 16.03.19 20:07
Оценка:
Здравствуйте, Lanjeron32, Вы писали:

L>
struct str { template<bool B> str() {} };

  шутка
#include <iostream>

#define B =true

struct str {
template<bool B> str() {}
};
extern str a;

str a = str();

int main(int argc, char* argv[])
{
    std::cout << "ok\n";
    return 0;
}


Если речь о том, чтобы попытаться вызвать конструктор template<bool B> str() извне, то, насколько мне известно, такой вызов не поддерживается. Впрочем, изнутри класса он тоже не поддерживается.
Есть две конструкции, где такой конструктор имел бы какой-то смысл и его можно было бы вызывать: внутри placement new и для вызова конструктора делегирования.
Например:
struct str
{
  template<bool B> str() {}

  str(int n) : str::str<true>{}
  str(char* p) : str::str<false>{}

};

Но всё это настолько малозначительно, что никому не нужно.
И каждый день — без права на ошибку...
Re[2]: Впал в ступор увидев такое
От: rg45 СССР  
Дата: 16.03.19 20:25
Оценка:
Здравствуйте, B0FEE664, Вы писали:


BFE>Если речь о том, чтобы попытаться вызвать конструктор template<bool B> str() извне, то, насколько мне известно, такой вызов не поддерживается. Впрочем, изнутри класса он тоже не поддерживается.


Дьявол, как обычно, прячется в мелочах. Задача — создать объект данного класса. А каким именно конструктором, об этом никто ничего не говорил.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 16.03.2019 20:30 rg45 . Предыдущая версия .
Re[3]: Впал в ступор увидев такое
От: B0FEE664  
Дата: 16.03.19 20:37
Оценка:
Здравствуйте, rg45, Вы писали:

R>Дьявол, как обычно, прячется в мелочах. Задача — создать объект данного класса. А каким именно конструктором, об этом никто ничего не говорил.


См. шутка
И каждый день — без права на ошибку...
Re[8]: Впал в ступор увидев такое
От: σ  
Дата: 17.03.19 07:29
Оценка: 13 (2)
R>То есть, UB, все-таки, правильно я понимаю?
Комитет решил, что инициализация объекта самим собой с использованием конструктора копий сама по себе к UB не приводит http://wg21.link/cwg363 (но UB может возникнуть, например, из-за чтения indeterminate value из дата мемберов).
Правда, решил он давно и через ~год появился другой issue http://wg21.link/cwg453, который пока не закрыт и который имеет отношение к такой инициализации самим собой.
Отредактировано 17.03.2019 7:30 σ . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.