Pull to refresh

Comments 19

UFO just landed and posted this here
boost 4.6? Вы подразумевали 1.46? Если да, то почему такой старый? Если нет, то что за буст вы имели в виду?
UFO just landed and posted this here
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 тоже всё будет компилироваться.

#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.
UFO just landed and posted this here
UFO just landed and posted this here
Установил 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 нет. Хорошо это или плохо, я не знаю.
UFO just landed and posted this here
Да не переживайте Вы так, я сам с gcc 3.4.6 и бустом 1.49 застрял похоже надолго (mmu-less armv4 железка, похоже больше ничего на ней и не взлетит).
Всё-таки это неявно генерируемый конструктор, а не неявный конструктор.
Согласен, было огромное желание подсократить количество текста в ячейках. Я подумаю как лучше представить, или просто небольшую легенду с допущениями или всё же полный вариант. С другой стороны некий каламбур получается, если заменить синонимами: Неявно генерируемый конструктор не генерируется. В любом случае — я вас услышал.
По тексту исправился. На картинках пока решил не трогать. Если кто хочет — SVG есть, в Inkscape на ура правится.
UFO just landed and posted this here
Так можно просто другую копию сделать. Проблем нет. Попробуйте глянуть c++11-move-assignment-solid.svg что по ссылке на исходники. Если понравится, можно скорректировать и второй и пусть будет на любителя.
Я запутался.
Есть класс (структура, не важно):
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 НЕ вызывается

Я окончательно запутался. Пошёл смотреть стандарт :(
Попробую на пальцах, при помощи аналогии:
#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. Конечно, пример натянутый, но вроде понятнее становится.
Я просто думал, что смогу для себя объяснить это в рамках overload resolution (Вот хорошее видео от Stephan T. Lavavej — Overload Resolution).

Вроде как даже нашёл: 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.

Но это не то, скорее всего
Кстати да, очень неплохая презентация.
Sign up to leave a comment.

Articles