Комментарии 19
НЛО прилетело и опубликовало эту надпись здесь
boost 4.6? Вы подразумевали 1.46? Если да, то почему такой старый? Если нет, то что за буст вы имели в виду?
+4
НЛО прилетело и опубликовало эту надпись здесь
Debian Wheezy, Boost 1.49. Мне удается скомпилировать следующий код версиями gcc 4.4, 4.6, 4.7, 4.8, 4.9 (из Debian Wheezy и Jessie) как с опцией -std=c++11 / -std=c++0x так и без неё. Подозреваю, что на Squeeze с его Boost 1.42 тоже всё будет компилироваться.
Кстати, что за boost::shared_pointer.cpp? Насколько я помню, shared_pointer реализован как header-only.
#include <string>
#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr<std::string> StringPtr;
StringPtr f() {
return StringPtr(new std::string);
}
int main() {
StringPtr ptr1(new std::string);
StringPtr ptr2 = ptr1;
StringPtr ptr3 = f();
}
Кстати, что за boost::shared_pointer.cpp? Насколько я помню, shared_pointer реализован как header-only.
0
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Установил Debian Squeeze в виртуалку, поставил туда Boost 1.42 и gcc 4.4. Компилируется со стандартными опциями и с -std=c++0x. Установил туда gcc-4.9 из Debian Jessie. Попробовал скомпилировать c -std=c++11, вот тут действительно получилась ошибка. А без -std=c++11 всё компилируется.
Кстати, clang 3.4 из Debian Jessie успешно компилирует этот код против Boost 1.42 как с опцией -std=c++11, так и без неё. Возможно, clang более либерален к коду в некотором смысле. Например, конструирование std::ifstream из std::string в clang компилируется, а в gcc нет. Хорошо это или плохо, я не знаю.
Кстати, clang 3.4 из Debian Jessie успешно компилирует этот код против Boost 1.42 как с опцией -std=c++11, так и без неё. Возможно, clang более либерален к коду в некотором смысле. Например, конструирование std::ifstream из std::string в clang компилируется, а в gcc нет. Хорошо это или плохо, я не знаю.
+1
Да не переживайте Вы так, я сам с gcc 3.4.6 и бустом 1.49 застрял похоже надолго (mmu-less armv4 железка, похоже больше ничего на ней и не взлетит).
0
Всё-таки это неявно генерируемый конструктор, а не неявный конструктор.
0
Согласен, было огромное желание подсократить количество текста в ячейках. Я подумаю как лучше представить, или просто небольшую легенду с допущениями или всё же полный вариант. С другой стороны некий каламбур получается, если заменить синонимами: Неявно генерируемый конструктор не генерируется. В любом случае — я вас услышал.
0
НЛО прилетело и опубликовало эту надпись здесь
Я запутался.
Есть класс (структура, не важно):
В этом случае неявный move-constructor не создаётся (По схеме: дважды Нет).
Должен ли компилироваться следующий код?
Ответ — всё в порядке — компилируется и вызывается копирующий конструктор:
Почему? Я как-то не правильно понимаю когда вызывается copy ctor? (Copy constructors):
Если же явно попросить компилятор сгенерировать move-конструктор, то уже действительно вызывается move-конструктор:
Если же явно запретить компилятору генерировать move-конструктор:
Тогда уже компилятор ругается!
Что получается:
Если move-конструктор неявно НЕ сгенерирован, то вызывается copy-constructor
Если move-конструктор явно помечен через
Я окончательно запутался. Пошёл смотреть стандарт :(
Есть класс (структура, не важно):
struct Test
{
Test() : s("s") {}
Test(const Test& other) : s(other.s) { puts("Test(const Test& other)"); }
std::string s;
};
В этом случае неявный move-constructor не создаётся (По схеме: дважды Нет).
Должен ли компилироваться следующий код?
int main()
{
Test t1{};
Test t2(std::move(t1));
puts(t1.s.c_str());
puts(t2.s.c_str());
return 0;
}
Ответ — всё в порядке — компилируется и вызывается копирующий конструктор:
Test(const Test& other)
s
s
Почему? Я как-то не правильно понимаю когда вызывается copy ctor? (Copy constructors):
The copy constructor is called whenever an object is initialized from another object of the same type, which includes
initialization, T a = b; or T a(b);, where b is of type T
function argument passing: f(a);, where a is of type T and f is void f(T t)
function return: return a; inside a function such as T f(), where a is of type T, which has no move constructor.
Если же явно попросить компилятор сгенерировать move-конструктор, то уже действительно вызывается move-конструктор:
struct Test
{
Test() : s("s") {}
Test(const Test& other) : s(other.s) { puts("Test(const Test& other)"); }
Test(Test&& other) = default;
std::string s;
};
//...
s
Если же явно запретить компилятору генерировать move-конструктор:
struct Test
{
Test() : s("s") {}
Test(const Test& other) : s(other.s) { puts("Test(const Test& other)"); }
Test(Test&& other) = delete;
std::string s;
};
Тогда уже компилятор ругается!
Что получается:
Test t2(std::move(t1));
Если move-конструктор неявно НЕ сгенерирован, то вызывается copy-constructor
Если move-конструктор явно помечен через
delete
, то copy-constructor НЕ вызываетсяЯ окончательно запутался. Пошёл смотреть стандарт :(
0
Попробую на пальцах, при помощи аналогии:
Получается, что в первом случае (Foo) int приведётся к char (без ворнингов только потому, что значение известно компилятору и оно помещается в char). Можешь считать отсутствие метода foo(int) как отсутствие move-ctor при присутсвии copy-ctor. Случай с Bar можно рассматривать как аналогию delete для move-ctor. Конечно, пример натянутый, но вроде понятнее становится.
#include <iostream>
using namespace std;
struct Foo
{
void foo(char a)
{
cout << (int)a << endl;
}
};
struct Bar
{
void bar(char a)
{
cout << (int)a << endl;
}
void bar(int a); // да-да, оно только объхявлено
};
int main()
{
char a = 100;
int b = 50;
Foo foo;
Bar bar;
foo.foo(a); // ок, печатает 100
foo.foo(b); // ок, печатает 50
bar.bar(a); // ok, печатает 100
bar.bar(b); // ошибка копиляции
return 0;
}
Получается, что в первом случае (Foo) int приведётся к char (без ворнингов только потому, что значение известно компилятору и оно помещается в char). Можешь считать отсутствие метода foo(int) как отсутствие move-ctor при присутсвии copy-ctor. Случай с Bar можно рассматривать как аналогию delete для move-ctor. Конечно, пример натянутый, но вроде понятнее становится.
0
Я просто думал, что смогу для себя объяснить это в рамках overload resolution (Вот хорошее видео от Stephan T. Lavavej — Overload Resolution).
Вроде как даже нашёл: 13.3.1.4 Copy-initialization of class by user-defined conversion (n3797)
И 13.3.1 Candidate functions and argument lists:
Но это не то, скорее всего
Вроде как даже нашёл: 13.3.1.4 Copy-initialization of class by user-defined conversion (n3797)
...the candidate functions are selected as follows:
...When initializing a temporary to be bound to the first parameter
of a constructor that takes a reference to possibly cv-qualified T as its first argument, called with a
single argument in the context of direct-initialization of an object of type “cv2 T”, explicit conversion
functions are also considered…
И 13.3.1 Candidate functions and argument lists:
A defaulted move constructor or assignment operator (12.8) that is defined as deleted is excluded from the
set of candidate functions in all contexts.
Но это не то, скорее всего
0
На ACCU 2014 была хорошая презентация на эту тему:
Everything You Ever Wanted To Know About Move Semantics. В частности, слайды с 19 по 30.
Everything You Ever Wanted To Know About Move Semantics. В частности, слайды с 19 по 30.
+1
Зарегистрируйтесь на Хабре , чтобы оставить комментарий
Пополняем шпаргалки по C++: неявно-генерируемые перемещающий конструктор и оператор присваивания