2012-09-03 2 views
3

저는 이동 생성자에 대해 교육하고 과제를 옮기기 위해 C++ 11의이 기능을 시작하도록 학생들을 유도하려고합니다. 나는 컴파일러가 대부분의 경우 이동 (또는 일반) 구조를 최적화하여 작업시이를 볼 수 없도록 (이 사이트의 다른 곳에서) 설명했다. gcc 4.7.0을 사용하면 -fno-elide-constructors 옵션이 해제되며 이동 작업이 일어나는 것을 볼 수 있습니다. 하지만 그 같은 플래그는 clang 옵션으로 (?)로 가정하고 clang, C++ 11 및 stdC++을 사용하여 Xcode 4.4.1에서 "Other C++ flags"로 지정하면 분명히 반환 된 값이 복사되지 않습니다. 또는 전혀 이동! 아주 멀리하지 않는 그 소리와 -fno-생략하다 생성자이 실행-fno-elide-constructors가 설정되어 있으면 clang Xcode 4.4.1 버그가 있습니까?

#include <iostream> 
using namespace std; 

class Array_Exception { 
public: 
Array_Exception (int v, const char * msg) : 
    value (v), msg_ptr(msg) {} 

int value; 
const char * msg_ptr; 
}; 

class Array { 
public: 
Array() : size(0), ptr(nullptr), serial_number(++counter) { 
    cout << "Array " << serial_number << " default constructed"; 
    } 

Array(int size_) : size(size_), serial_number(++counter) { 
    if(size <= 0) 
     throw Array_Exception(size, "size must be greater than 0"); 
    ptr = new int[size]; 
    cout << "Array " << serial_number << " constructed" << endl; 
    } 

Array(const Array& source) : size(source.size), ptr(new int[size]), serial_number(++counter) { 
    for (int i = 0; i < size; i++) 
     ptr[i] = source.ptr[i]; 
    cout << "Array " << serial_number << " constructed from " << source.serial_number << endl; 
    } 

// move constructor - take the guts from the source and leave it in a safely destructable state 
Array(Array&& source) : size(source.size), ptr(source.ptr), serial_number(++counter) { 
    source.size = 0; 
    source.ptr = nullptr; 
    cout << "Array " << serial_number << " move constructed from " << source.serial_number << endl; 
    } 

// copy the data from rhs into lhs object using copy-swap 
Array& operator= (const Array& source) { 
    Array temp(source); 
    swap(temp); 
    cout << "Array " << serial_number << " assigned from " << source.serial_number << endl; 
    return *this; 
    } 

// move assignment just swaps source with this. 
Array& operator= (Array&& source) { 
    swap(source); 
    cout << "Array " << serial_number << " move assigned from " << source.serial_number << endl; 
    return *this; 
    } 

// swap the member variable values of this object with the other (serial_numbers are NOT swapped) 
void swap(Array& other) { 
    int t_size = size; // could use std::swap 
    size = other.size; 
    other.size = t_size; 
    int * t_ptr = ptr; 
    ptr = other.ptr; 
    other.ptr = t_ptr; 
    }  

~Array() { 
    delete[] ptr; 
    cout << "Array " << serial_number << " destroyed" << endl; 
    } 

int get_size() const {return size;} 

// overloaded plus operator returns an Array containing the sum of the two 
Array operator+ (const Array& rhs) { // "this" object is lhs 
    // must have the same size 
    if(size != rhs.get_size()) 
     throw Array_Exception(size, "LHS and RHS must have the same size for +"); 
    Array result(size); 
    for(int i = 0; i < size; i++) 
     result[i] = ptr[i]+rhs[i]; 
    return result; 
    } 

const int& operator[] (int index) const { 
    if (index < 0 || index > size - 1) { 
     throw Array_Exception(index, "Index out of range"); 
     } 
    return ptr[index]; 
    } 

int& operator[] (int index) { 
    if (index < 0 || index > size - 1) { 
     throw Array_Exception(index, "Index out of range"); 
     } 
    return ptr[index]; 
    } 

private: 
int size; 
int* ptr; 
int serial_number; 
static int counter; 
}; 

int Array::counter = 0; 

void print_all(const char * msg, const Array& a); 
Array reverse_contents(Array a); // call and return by value 

int main() 
{ 

Array a(5), b(5), c(5); 
for (int i = 0; i < 5; i++) 
    a[i] = i; // 0, 1, 2, 3, 4 

try {    
    cout << "\ncall by value and assign from returned value:" << endl; 
    print_all("a has", a); 
    b = reverse_contents(a); 
    print_all("b has reversed", b); 

    cout << "\nassign from rvalue expression" << endl; 
    c = a + b; 
    print_all("c has sum", c); 

    cout << "\nconstruct from rvalue expression" << endl; 
    Array e(a + c); 
    print_all("e has copy of a + c", e); 

    cout << "\nconstruct from function return value" << endl; 
    Array d(reverse_contents(a)); 
    print_all("d has returned reverse of a", d); 

    } 

catch (Array_Exception& x) { 
    cout << x.msg_ptr << ' ' << x.value << endl; 
    } 

cout << "\nDone!" << endl; 
} 

void print_all(const char * msg, const Array& a) { 
cout << msg << ": "; 
for(int i= 0; i < a.get_size(); i++) 
    cout << a[i] << ' '; 
cout << endl; 
} 

Array reverse_contents(Array a) { 
int n = a.get_size(); 
Array result(n); 

for(int i = 0; i < n; i++) { 
    result[i] = a[n-i-1]; 
    } 
return result; 
} 

: 여기

는 전체 테스트 코드와 출력 문제가 발생하는 경우 주석입니다 호출에서 로컬 변수 함수는 반환 동안 파괴됩니다 그리고 우리는 가짜 객체에서 이동 할당을하고 결국 : b는 그 안에 아무것도하지 않기 때문에

Array 1 constructed 
Array 2 constructed 
Array 3 constructed 

call by value and assign from returned value: 
a has: 0 1 2 3 4 
Array 4 constructed from 1 
Array 5 constructed 
Array 5 destroyed << local Array has been destructed 
Array 2 move assigned from 0 << Array with serial_number == 0 is bogus object 
Array 0 destroyed << bogus object destroyed here 
Array 4 destroyed 
b has reversed: << nothing in the returned result 

프로그램은 다음 테스트에 중단.

GCC 4.7.0에서 실행 동일한 코드를 이해하는 것와 쇼는 직장에서 건축을 이동 : g ++ -std = C++ 11 * 통화 당 -fno-생략하다 - 생성자

Array 1 constructed 
Array 2 constructed 
Array 3 constructed 

call by value and assign from returned value: 
a has: 0 1 2 3 4 
Array 4 constructed from 1 
Array 5 constructed 
Array 6 move constructed from 5 
Array 5 destroyed 
Array 2 move assigned from 6 
Array 6 destroyed 
Array 4 destroyed 
b has reversed: 4 3 2 1 0 

assign from rvalue expression 
Array 7 constructed 
Array 8 move constructed from 7 
Array 7 destroyed 
Array 3 move assigned from 8 
Array 8 destroyed 
c has sum: 4 4 4 4 4 

construct from rvalue expression 
Array 9 constructed 
Array 10 move constructed from 9 
Array 9 destroyed 
Array 11 move constructed from 10 
Array 10 destroyed 
e has copy of a + c: 4 5 6 7 8 

construct from function return value 
Array 12 constructed from 1 
Array 13 constructed 
Array 14 move constructed from 13 
Array 13 destroyed 
Array 15 move constructed from 14 
Array 14 destroyed 
Array 12 destroyed 
d has returned reverse of a: 4 3 2 1 0 
Array 15 destroyed 
Array 11 destroyed 

Done! 
Array 3 destroyed 
Array 2 destroyed 
Array 1 destroyed 

을 따라서 elion을 끄면 gcc 4.7에서 합리적인 결과를 얻을 수 있지만 clang에서는 깨진 코드가 생성됩니다. 이것은 clang의 버그입니까, 아니면 clang에서 실제로 지원되지 않는 컴파일러 옵션입니까?

답변

3

이이 연타 버그 다음과 같습니다

http://llvm.org/bugs/show_bug.cgi?id=12208

+0

감사합니다! 어떤 이유로 든 내 검색에서 찾지 못했습니다. 다음 번에 llvm 버그 목록을 별도로 살펴 보겠습니다! 최소한 gcc 4.7 작품은 교육 목적으로 도움이 될 것입니다. – user1628444

관련 문제