Он прекрасно компилируется в MSVC 2010 и в Clang — видимо, срабатывает оптимизация возвращаемого значения и копирующий конструктор не требуется.
Однако код не компилируется в MSVC 2015 — пишет "referencing deleted function", указывая на копирующий конструктор. Конструкция
return {};
спасает ситуацию, но она в свою очередь не компилируется в MSVC 2010.
Вопрос — как красиво выйти из ситуации, чтобы код собирался одновременно под 2010, 2015 и clang?
Условную компиляцию и отказ от noncopyable не предлагать
UPD:
Проблема решена — добавлен конструктор перемещения.
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
B>Он прекрасно компилируется в MSVC 2010 и в Clang — видимо, срабатывает оптимизация возвращаемого значения и копирующий конструктор не требуется.
ничего себе. и, что, даже предупреждения не выдает, что "на самом деле у вас ошибка, но после нашей оптимизации и выбрасывания кода, все можно считать ок"?
B>Однако код не компилируется в MSVC 2015 — пишет "referencing deleted function", указывая на копирующий конструктор.
фух, значит, все-таки это был баг vs2010 (возможность компиляции такой явно некорректной проги)
Конструкция B>
B>return MyClass{}
B>
спасает ситуацию, но она в свою очередь не компилируется в MSVC 2010.
кхм... а точно return MyClass{}, а не return {} ? Иначе я опять начинаю сомневаться в компиляторе (ведь MyClass{} же равносильно MyClass())
B>Вопрос — как красиво выйти из ситуации, чтобы код собирался одновременно под 2010, 2015 и clang? B>Условную компиляцию и отказ от noncopyable не предлагать
странный вопрос. вы делает объект некопируемым и при этом хотите его скопировать. может, все-таки пересмотреть, что вам нужно на самом деле.
Здравствуйте, _hum_, Вы писали:
__>ничего себе. и, что, даже предупреждения не выдает, что "на самом деле у вас ошибка, но после нашей оптимизации и выбрасывания кода, все можно считать ок"?
Да, без предупреждений.
__>кхм... а точно return MyClass{}, а не return {} ? Иначе я опять начинаю сомневаться в компиляторе (ведь MyClass{} же равносильно MyClass())
Да, просто {} — описался.
B>>Вопрос — как красиво выйти из ситуации, чтобы код собирался одновременно под 2010, 2015 и clang? B>>Условную компиляцию и отказ от noncopyable не предлагать __>странный вопрос. вы делает объект некопируемым и при этом хотите его скопировать. может, все-таки пересмотреть, что вам нужно на самом деле.
Здесь нет потребности в копировании.
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Здравствуйте, Basil2, Вы писали:
B>Здравствуйте, _hum_, Вы писали:
B>>>Вопрос — как красиво выйти из ситуации, чтобы код собирался одновременно под 2010, 2015 и clang? B>>>Условную компиляцию и отказ от noncopyable не предлагать __>>странный вопрос. вы делает объект некопируемым и при этом хотите его скопировать. может, все-таки пересмотреть, что вам нужно на самом деле.
B>Здесь нет потребности в копировании.
а в чем есть потребность? зачем вы пытаетесь вернуть объект по значению, а не по ссылке, например?
Здравствуйте, Basil2, Вы писали:
B>Здравствуйте, uzhas, Вы писали:
U>>move конструктор объявить не хотите?
B>Спасибо, про самый простой способ я и не подумал Точнее подумал, но думал что этого в 2010 еще нет...
B>Вопрос — как красиво выйти из ситуации, чтобы код собирался одновременно под 2010, 2015 и clang? B>Условную компиляцию и отказ от noncopyable не предлагать
Не уверен, что это красиво. Ибо совершается избыточная работа по перемещению. На мой взгляд, красиво — это либо создать его динамически и вернуть указатель/ссылку (например, через фабрику). Либо конструирование объекта по ссылке, вроде
void ConstructMyObject(MyObject & construct_this) {
//инициализация объекта
//...
}
int main(int argc, char * argv[]) {
MyObject object();
ConstructMyObject(object);
}
Третий подход, который видится мне, состоит в том, чтобы создать класс — хэндл, ссылочный класс, который бы автоматически приводился бы к данному. Тогда класс динамически можно было бы создать в любом месте, а копировать на него ссылочный класс. Специфично, но иногда интересно.
Четвёртый подход — это синглтон с меткой
template <typename Data, typename Label> Singleton { // синглтон, шаблонный параметр Label нигде не используется, но позволяет создавать несколько синглтонов типа Data
//реализация синглтона, доступ через operator()
};
class MyObjectData : public NonCopyable {
//определение своего класса
};
struct MyObject_ForUsingInSortAlgorithm_Label {}; // пустой класс, который играет роль меткиtypedef Singleton<MyObjectData, MyObject_ForUsingInSortAlgorithm_Label> MyObject;
void MyObjectInitialize (MyObject data){
data().set_some_arg(10);
data().set_some_string_arg("Follow the white rabbit");
data().set_other_string_arg("Open your mind");
}; //Вуаля! класс можно передавать по значению, но нельзя скопировать, и реального копирования не происходит
Для того, чтобы понять, что из этого может тебе пригодится, или предложить альтернативное решение, нужно знать твои цели.
Здравствуйте, Molchalnik, Вы писали:
M>Не уверен, что это красиво. Ибо совершается избыточная работа по перемещению.
Тут по сути нет работы, это же не копирование.
M>На мой взгляд, красиво — это либо создать его динамически и вернуть указатель/ссылку (например, через фабрику).
Вариант с unique_ptr рассматривался, но решили не менять сигнатуру функции, ибо потом пришлось бы править ее использование.
Все остальное — имхо настолько оверкилл, что даже дурной тон это использовать.
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Здравствуйте, Basil2, Вы писали:
B>Здравствуйте, Molchalnik, Вы писали:
M>>Не уверен, что это красиво. Ибо совершается избыточная работа по перемещению.
B>Тут по сути нет работы, это же не копирование.
Зависит от типа объекта. Если нет копирования — значит, объект лишь оболочка над ссылкой на данные. Т.е. мы имеем вариант со ссылкой, только спрятанный в объект
B>Все остальное — имхо настолько оверкилл, что даже дурной тон это использовать.
смотря для каких целей
B>оверкилл
незнакомое слово. что значит?
B>даже дурной тон это использовать.
Обоснуй?
Здравствуйте, Molchalnik, Вы писали:
M>>>Не уверен, что это красиво. Ибо совершается избыточная работа по перемещению. B>>Тут по сути нет работы, это же не копирование. M>Зависит от типа объекта. Если нет копирования — значит, объект лишь оболочка над ссылкой на данные. Т.е. мы имеем вариант со ссылкой, только спрятанный в объект
Прочитайте про move-семантику.
B>>Все остальное — имхо настолько оверкилл, что даже дурной тон это использовать. M>смотря для каких целей
Для заявленных
B>>оверкилл M>незнакомое слово. что значит? https://ru.wiktionary.org/wiki/overkill
3) перен. перегиб, крайность; излишество, чрезмерность
B>>даже дурной тон это использовать. M>Обоснуй?
Зачем делать сложный шаблонный паттерн синглетом, когдо можно не делать его и получить все тоже самое без лишних сущностей и шаблонов?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Здравствуйте, Basil2, Вы писали:
B>Прочитайте про move-семантику.
Я знаком с мов-семантикой. И именно поэтому утверждаю, что мов-семантика — это либо скрытый в глубинах объекта указатель, либо лишнее копирование.
Например, если у вас объект стринг, в нём есть указатель на данные, собственно, на массив символов. И тогда копирующий конструктор создаст новый пул памяти длиной со строку и скопирует в него данные из источника. Преимущество мов-семантики в том, что она просто скопирует указатель в новый объект, а старый объект занулит, не удаляя массив символов. Это в разы быстрее. Но что вы будете делать, если ваша мов-семантика столкнётся с объектом — пулом данных без всяких указателей? ничего. Вызовет копирующий конструктор или сдублирует его код в своей имплементации.
именно поэтому мов — семантика НЕ МОЖЕТ БЫТЬ УНИВЕРСАЛЬНЫМ РЕШЕНИЕМ для некопируемых объектов. Потому что негарантировано, что в ОБЩЕМ случае мов-семантика эффективна.
Поэтому для того, чтобы получить точный, хороший ответ на этот вопрос, вы должны описать свойства объектов, для которых вы будете это использовать — любые объекты или лишь некоторые и/или цели, почему вам вдруг понадобилось возвращать некопируемый объект из функции. Тогда можно будет подобрать решение именно под вашу ситуацию.
Заранее хочу опровергнуть рассуждения на тему "так не бывает на практике, поэтому об этом можно не думать". Бывает!!! И чтобы показать это, приведу вам вполне практический пример из жизни — некопируемый объект, для которого неприемлема мов-семантика. т.е. некопируемый и НЕПЕРЕМЕЩАЕМЫЙ объект.
Представим себе, что мы пишем парсер некого формата файла. В этом случае часто получается, что у нас в памяти оказывается пул данных (длинна пула данных неизвестна на этапе компиляции), но при этом начало этого файла — заголовок заранее известной длинны и с известными полями. В этом случае довольно часто можно увидеть следующий код:
Прошу обратить внимание на идиому Byte data[0];
Это классический трюк для работы с объектом, чья длина известна только во время исполнения кода.
При этом данный объект является классическим некопируемым объектом — просто потому, что копировать его не имеет смысла, а если это произойдёт, это может привести к печальным для производительности последствиям — ведь его длина может достигать полумегабайта, например. поэтому имеет смысл делать его некопируемым, а передавать на него именно указатель. В данном случае, кстати, синглтон ни к селу, ни к городу. Но это не означает, что синглтон перегиб — просто синглтон перегиб для ДАННОГО случая, и , по-видимому, и для вашего.
B>>>Все остальное — имхо настолько оверкилл, что даже дурной тон это использовать. M>>смотря для каких целей B>Для заявленных
Имхо: заявлены лишь средства. Хочу возвращать non-copyable объект. Для чего возвращать — это и есть цель. О ней умолчали.
B>3) перен. перегиб, крайность; излишество, чрезмерность
Спасибо. Лично мне русское слово "перегиб" нравится больше. Меньше понтов, больше смысла, патриотично. Но буду знать теперь, what is it
B>>>даже дурной тон это использовать. M>>Обоснуй? B>Зачем делать сложный шаблонный паттерн синглетом, когдо можно не делать его и получить все тоже самое без лишних сущностей и шаблонов?
Я привёл выше пример, когда нельзя получить всё тоже самое с семантикой перемещений (мов-семантикой). Так же можно придумать и практически существующую задачу, где синглтон будет удобнее всего. А синглтон не нужно реализовывать — он должен быть "всегда с собой" — реализован один раз и сохранён в библиотеке.
Резюме: для вашего случая, я согласен, предложенные рецепты — перегиб. Но существуют ситуации, когда данные рецепты перегибом не будут, а будут красивым и органичным решением, и чтобы понять, что хорошо для вашего случая — нужно получить больше информации о том, для каких объектов поставлена задача, и для каких целей вам нужно возвращать некопируемый объект.
Здравствуйте, ononim, Вы писали:
B>>Условную компиляцию и отказ от noncopyable не предлагать O>А если на принимающей стороне принимать в ссылку: O>
O>const MyClass &r = foo();
O>
O>? (самому лень проверять)
Всё равно нужен конструктор копирования/перемещения, если только внутри не используется copy-list-initialization.
Эта const& убирает только одно (внешнее) копирование/перемещение из двух.
O>ЗЫ Работоспособность этой конструкции (именно с const) гарантируется стандартом.