Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
1 / 1 / 0
Регистрация: 20.09.2018
Сообщений: 63

Оператор преобразования типа для неконстантной ссылки

23.09.2023, 15:00. Показов 2035. Ответов 52
Метки c++ (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Я работаю над большим приложением, задействующим несколько сторонних библиотек. В каждой библиотеке реализован свой класс математического вектора. При этом, структуры и методы из этих библиотек в моем приложении обмениваются данными в виде этих векторов. То есть, я могу получить вектор методом из одной библиотеки, а потом передать его методу в другую библиотеку.
Для того, чтобы каждый раз не преобразовывать один вектор в другой (суть их одна и та же: три компоненты - x, y, z), я сделал класс-адаптер, в котором перегрузил операторы преобразования типа, которые могут возвращать созданные объекты-векторы из обеих библиотек по значению или по константной ссылке, все прекрасно работает.
Теперь появились методы, которые хотят принимать неконстантную ссылку на вектор, и я не совсем понимаю, как мне быть. Мой адаптер выглядит примерно так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//forward declaration
struct Lib1Vector;
struct Lib2Vector;
 
struct MyAdapter
{
    float x;
    float y;
    float z;
private:
    Lib1Vector* lib1Vector;
    Lib2Vector* lib2Vector;
public:
    ...// конструкторы, деструктор
    operator Lib1Vector() const;
    operator Lib2Vector() const;
    operator const Lib1Vector()& const;
    operator const Lib2Vector()& const;
    
}
Если некая функция получит доступ к полю, например, lib1Vector и изменит его значение (по неконстантной ссылке), то поля x,y,z, которые единственные ранее использовались для изменения состояния вектора, будут хранить устаревшие значения. Подскажите, пожалуйста, как мне решить данную проблему. Быть может, сам подход к ней в корне неверен. Спасибо
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
23.09.2023, 15:00
Ответы с готовыми решениями:

Оператор преобразования типа в классах
Допустим, есть три класса: //Фигура class figure; //Дамка class king { public: void step(figure&);

Оператор преобразования типа в char*
Всем привет! Вот у меня есть готовый код для класса Complex #include <iostream> #include <cmath> using namespace std; ...

Оператор динамического преобразования типа возвращает ссылку NULL
Доброго всем времени суток. Пытаюсь разобраться с работой оператора dynamic_cast using namespace std; class parentClass { ...

52
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
25.09.2023, 22:59
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от DrOffset Посмотреть сообщение
Может лучше, как обычно бывало раньше, вы возьмете время подумать и сами все увидите?
Наводящий вопрос вам уже задали:
DrOffset, на этот вопрос я уже ответил. Дальше что?
Вы хотите сказать что агрегация с отношением - невладение (неуправляемая агрегация), это порок?
Ссылка ли, указатель ли - неважно. Всё может стать невалидным при преждевременном уничтожении цели. И что?
Пока объект - цель жива, всё должно работать и UB нет. Компилятору до этого нет дела от слова - совсем.
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
25.09.2023, 23:07
Цитата Сообщение от IGPIGP Посмотреть сообщение
Пока объект - цель жива, всё должно работать и UB нет.
Так он не жив. vec помер сразу по выходу из конструктора, а объект остался хранить ссылки на его мертвое содержимое.

Добавлено через 5 минут
C++
1
2
3
4
5
6
    BaseAdapter12(vec1 vec)
        : x(vec.x)
        , y(vec.y)
        , z(vec.z)      
        {
        } // тут vec умер. ссылки x,y,z - живы и ссылаются на его бренное тело.
Исправить это просто, достаточно добавить &:
C++
1
2
3
4
5
6
    BaseAdapter12(vec1& vec) // <--- ссылка
        : x(vec.x)
        , y(vec.y)
        , z(vec.z)      
        {
        }
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
25.09.2023, 23:10
Цитата Сообщение от DrOffset Посмотреть сообщение
Так он не жив. vec помер сразу по выходу из конструктора, а объект остался хранить ссылки на его мертвое содержимое.
Конструктор принимал ссылку на объект. Он никак его убить не может этим фактом. Распечатайте его адрес в функции main (она определяет время жизни и - да, в многопоточной задаче, где main завершится раньше потока которуму отдали такую ссылку - по std::ref - то есть намернно суицидально, будет больно) и распечатйте в конструкторе и вы всё увидите.
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
25.09.2023, 23:13
Цитата Сообщение от IGPIGP Посмотреть сообщение
выводит неинициализированную чушь, от nan и до 1.83e-81
Собственно поэтому и выводит это. Ссылки берут мусор из невалидной памяти при попытке доступа.
GCC исправно диагностирует это, кстати:
Code
1
2
3
prog.cc: In constructor 'BaseAdapter12::BaseAdapter12(vec1)':
prog.cc:26:11: warning: storing the address of local variable 'vec' in '*this.BaseAdapter12::z' [-Wdangling-pointer=]
   26 |         , z(vec.z)
https://wandbox.org/permlink/06E4CkKIsT9xTYRb
По ссылке как раз видно, что выводит чушь вроде 4.5793e-41. После добавления амперсанда все нормализуется.

Так что нет, это не баг, это ваш недосмотр.
Я не знаю зачем вы спорили, вероятно вы видели какой-то другой смысл в моих словах и другое место в вашем коде. Но место именно это, диагностика моими глазами и компилятором - совпадает. А также поведение нормализуется после вышеприведенных исправлений. UB как оно есть.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
25.09.2023, 23:14
Цитата Сообщение от DrOffset Посмотреть сообщение
Исправить это просто, достаточно добавить &:
у-у-пс - механическая ошибка...
Ну могли бы и раньше это сказать! Я был уверен что по ссылке принял. Щас пойду смотреть не исправится ли MinGW
Тогда микросфт творит чудо. Хотя да. Это чистейшее UB.
Да, теперь и из-под MinGW всё нормально вышло)
Спасибо)
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
25.09.2023, 23:21
Если в моем примере нет UB среди этих reinterpret_cast<>, и вектора автора standard layout и layout compatible, то может ему подойдет, где хранить сами данные, внутри адаптора или извне, это дело 5-е.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
 
struct V1;
struct V2;
 
struct Adapt{
private :
   V1* data;
public:
   float &x, &y, &z;
   Adapt(void* v);
 
   operator V1&(){
      return *reinterpret_cast<V1*>(data);
   }
   operator V2&(){
      return *reinterpret_cast<V2*>(data);
   }
};
 
struct V1{
   float x,y,z;
};
struct V2{
   float x,y,z;
};
std::ostream& operator<<(std::ostream& out, const Adapt& a){
   out << '(' << a.x << ", " << a.y << ", " << a.z << ')'<< std::endl;
   return out;
}
int main(){
   V1 v1{100,10,1};
   Adapt a(&v1);
   std::cout << a;
   
   V2 &v2 = a;
   v2 = V2{777, 0, 333};
   std::cout << a;
}
 
Adapt::Adapt(void* v)
   : data{reinterpret_cast<V1*>(v)}, x{data->x}, y{data->y}, z{data->z}{
}
Но как по мне, так проще просто конвертнуть функцией, там где нужно, как у woldemas, Оператор преобразования типа для неконстантной ссылки
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
25.09.2023, 23:22
danascully, в обоих конструкторах базового добавьте амперсанды в аргумнентах.
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
25.09.2023, 23:22
Цитата Сообщение от IGPIGP Посмотреть сообщение
Ну могли бы и раньше это сказать!
Сразу и сказали. Еще в сообщении 31.
Цитата Сообщение от DrOffset Посмотреть сообщение
У вас в коде dangling-references образованы в конструкторе BaseAdapter12, видимо поэтому и отказывался собирать.
Потом повторили в ообщении 33.
Цитата Сообщение от SmallEvil Посмотреть сообщение
У вас ссылки на несуществующий объект, после выхода из конструктора, так как они ограничены временем жизни внутри конструктора.
Вы просто слушать не хотели, начали агрессивно возражать.
Я между тем максимально корректно вас поправил. И даже дал вам возможность вместо спора со мной самому ошибку найти.
Цитата Сообщение от DrOffset Посмотреть сообщение
Может лучше, как обычно бывало раньше, вы возьмете время подумать и сами все увидите?
Так что нет. Именно в данной ситуации я сделал все возможное и чтобы сохранить дискуссию, и чтобы прийти к истине, и чтобы никого не обидеть.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
25.09.2023, 23:28
Цитата Сообщение от SmallEvil Посмотреть сообщение
V1* data;
Тогда уже void* лучше может быть. В этом подходе несколько сложнее обеспечить безопасность. У меня слабость в том, что оно лишь в рантайме вылезет если что. Или лепить функцию верификатор и звать каждый раз. Мутота...

Добавлено через 2 минуты
Цитата Сообщение от DrOffset Посмотреть сообщение
Сразу и сказали. Еще в сообщении 31.
Я был уверен, что по ссылке принял и всё обсуждение это подтверждает. Если бы ткнули носом прямо в это дело я бы и не стал спорить. С чем там спорить?
Я то думал, что предложенная мной схема (без учёта этой механической ошибки) содержит UB и сразу стал спорить. А нужно было одну строчку посмотреть.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
25.09.2023, 23:36
Цитата Сообщение от IGPIGP Посмотреть сообщение
Тогда уже void* лучше может быть.
Да можно и void.
Можно и два конструктора принимать каждый вектор, и операторы присваивания.
И можно, как я писал, создавать внутри Адаптора место для вектора.
Но суть не в этом.
Суть в том, что на cppreference одним примером про *reinterpret_cast<T*>(v); и какое то размытое к ему поисание, меня просто повергли в смятение, но в drafte я пока этому подтверждения не нашел, пока.
Вот пример :
The purpose of strict aliasing and related rules is to enable type-based alias analysis, which would be decimated if a program can validly create a situation where two pointers to unrelated types (e.g., an int* and a float*) could simultaneously exist and both can be used to load or store the same memory (see this email on SG12 reflector). Thus, any technique that is seemingly capable of creating such a situation necessarily invokes undefined behavior.

When it is needed to interpret the bytes of an object as a value of a different type, std::memcpy or std::bit_cast (since C++20) can be used:

C++
1
2
3
4
5
6
double d = 0.1;
std::int64_t n;
static_assert(sizeof n == sizeof d);
// n = *reinterpret_cast<std::int64_t*>(&d); // Undefined behavior
std::memcpy(&n, &d, sizeof d);               // OK
n = std::bit_cast<std::int64_t>(d);          // also OK
https://en.cppreference.com/w/... rpret_cast
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
26.09.2023, 00:07
SmallEvil, я исходил из того что vec1 и vec2 разные типы, хотя литерально они идентичны с точностью до статических методов. То есть, мой адаптер позволяет принимать любой из них, получать доступ к данным x,y,z и вызывать одноимённые статические методы. Но последние написаны разными библиотеками и их кода не видно. Вот и решил, что лучше их разделить, но юзать через адаптер как нечто родственное но не эквивалентное. Насколько это соответствует задаче, - решать ТС. Такой подход свободен от требований лайаут совместимости и более переносим с учётом будущих новых версий библиотек. Но решение несколько не компактное, хотя по ресурсам нетребовательное. Просто как вариант.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
26.09.2023, 00:49
Цитата Сообщение от IGPIGP Посмотреть сообщение
То есть, мой адаптер позволяет принимать любой из них, получать доступ к данным x,y,z и вызывать одноимённые статические методы.
Понятно.
Но ведь ТС хотел не один из них, а иметь возможность преобразования к обоим типам.
Может это можно достроить из ваших прокси, но я пока не вижу как.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
26.09.2023, 09:40
Цитата Сообщение от SmallEvil Посмотреть сообщение
Но ведь ТС хотел не один из них, а иметь возможность преобразования к обоим типам.
Нет. Он писал, что устал преобразовывать один к другому и написал адаптер, где присутствуют указатели на оба. Тут можно по-разному понять, чего он желает). Я думаю, что если статические методы абсолютно идентичны и есть уверенность, что ни один код не станет сравнивать указатели на них, то можно и reinterpret_cast'ить.
Цитата Сообщение от SmallEvil Посмотреть сообщение
Может это можно достроить из ваших прокси, но я пока не вижу как.
Это не нужно. Создать адаптер, который ссылается на оба типа как на один легко. А вот передать ссылку на этот один в функцию, ожидающую другой не выйдет без преобразования ссылки одного типа в ссылку другого. Последнее, мне не нравится и я разделил статические типы в пределах одного интерфейса (базовый класс, наследование, полиморфизм).
SmallEvil, оба подхода возможны. Можно и статически на шаблонах написать третий вариант. Он сможет брыкнуться во время компиляции, что является преимуществом. Но связывание интерфейса в рантайме будет потеряно.
Пусть ТС смотрит и решает. Мы тут диспутируем, а он пропал.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
26.09.2023, 09:40

Определить оператор преобразования типов из типа дробь в тип double
Добрый вечер, Я только начал обучаться на факультет С#; Такая задачка, я создал класс дробь с двумя параметрами RationalNumbers(int...

Странный порядок вызова конструкторов и передача временного обьекта в функцию в качестве неконстантной ссылки
Есть код //g++ 5.4.0 #include &lt;iostream&gt; struct foo { foo(int){std::cout &lt;&lt; &quot;int ctor&quot; &lt;&lt; std::endl;} foo()...

Оператор преобразования типа и его эквивалентные замены, поиск строки в текстовом файле , содержащей заданный
Господа, был бы очень признателен если бы кто то помог ответить на вапросы http://cs616225.vk.me/v616225102/122f8/5kAaFEGoDn0.jpg

Оператор new для возвращения ссылки
Здравствуйте Увидел такой код впервые и мне интересно: для чего он нужен? T* instance = freeList.Pop(); return new...

Функция для преобразования из типа float в char
Всем привет! Если у кого-то есть возможность подсказать, как из float преобразовать число с плавающей точкой (В моем случае 4,2) в char,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
53
Ответ Создать тему
Новые блоги и статьи
Оказывается, Unreal Engine позволяет качество на порядки выше, чем было в Lineedge
Etyuhibosecyu 05.07.2026
Жаль, конечно, что я не узнал об этом, пока Lineedge существовала, а то бы Noname2331 написал, что волки превращаются в пиксельную кашу, а я бы его попросил скачать какую-нибудь бриллиантовую или Pro. . .
Doom для терминала без стрельбы и монстров. 3D Raycasting на ascii.
dcc0 05.07.2026
Попросил нейронную сеть deepai. org написать рейкастинг 3D с библиотекой ncurses для Linux. Чтобы можно было ходить на стрелочки. Чтобы стены были отрисованы символами. Справилась. Первый вариант. . .
Установка статуса документа по условию
Maks 05.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "НарядПутевка" разработанного в КА2. Задача: в табличной части "Материалы" документа при записи автоматически устанавливать статус. . .
Сезонность и суточность закисления почв
anaschu 04.07.2026
200 часов это все равно моловато. Есть ситуации, но нестандартные, когда смена происходит за 5 лет. Но обычно это 50 лет и более. Наверное, закисление почвы происходит сезонно в средней. . .
В чем ценность человеческого опыта в глобальном смысле?
kumehtar 03.07.2026
Возможно, ценность человека не в том, что он однажды достигает мудрости, а в том, что он становится носителем карты пути. Он знает не только истину, но и последовательность внутренних изменений,. . .
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи. Через несколько переработок от PHP кода к C89 (надеюсь, 89). Но довольно запутанно получилось. Код для Linux. Но если убрать time и то, что с ним. . .
Сам себя обучал rest api
anaschu 02.07.2026
Педагогический лайфхак: Почему чистый REST API для ученика намного круче, чем готовые библиотеки Когда мы отказались от капризного JAR-файла AnyLogic и переписали код на стандартный HttpClient,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru