当-fno-elide-constructors设置时,clang Xcode 4.4.1 bug吗? [英] Is clang Xcode 4.4.1 buggy when -fno-elide-constructors is set?

查看:235
本文介绍了当-fno-elide-constructors设置时,clang Xcode 4.4.1 bug吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想教育自己在移动构造函数和移动分配,所以我可以让我的学生开始使用C ++ 11的这个功能。我看到(和解释在这个网站的其他地方)编译器将优化移动(或普通的)结构在大多数情况下,所以你不能看到它在工作。使用gcc 4.7.0,-fno-elide-constructors选项将关闭,你可以看到移动构建发生。但是同样的标志应该是(cl)选项,当我在Xcode 4.4.1中使用clang,c ++ 11和stdc ++将其指定为其他C ++标志时,显然返回的值不会被复制或移出了!

I'm trying to educate myself on move constructors and move assignment so I can get my students started on this feature of C++11. I've seen (and explained elsewhere on this site) that compilers will optimize away the move (or ordinary) construction in most cases so you can't see it at work. With gcc 4.7.0, the -fno-elide-constructors option will turn that off and you can see move construction happening. But that same flag is supposed(?) to be clang option, and when I specify it as "Other C++ flags" in Xcode 4.4.1 with clang, c++11, and stdc++, apparently a returned value doesn't get copied or moved out at all!

这是完整的测试代码和输出注释的问题发生的地方:

Here is the complete test code and the output annotated with where the problem happens:

#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; 
}

使用clang和-fno-elide构造函数运行不会很远:被调用函数中的局部变量在返回期间被破坏,我们最终从虚假对象中移动赋值:

Running this with clang and -fno-elide constructors doesn't get very far: the local variable in the called function gets destroyed during the return and we end up doing a move assignment from a bogus object:

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

程序在下一个测试中暂停,因为b没有任何内容。

The program halts in the next test because b doesn't have anything in it.

在gcc 4.7.0下运行的同样的代码似乎有意义,并显示了在工作中的移动构建:
g ++ -std = c ++ 11 *。 cpp -fno-elide-constructors

The same code running under gcc 4.7.0 seems to make sense and shows move construction at work: g++ -std=c++11 *.cpp -fno-elide-constructors

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

所以关闭elision在gcc 4.7中给出一个明智的结果,但在clang中产生破碎的代码。

So turning off elision gives a sensible result in gcc 4.7, but produces broken code in clang. Is this a bug in clang, or is that compiler option actually not supported in clang?

推荐答案

这个clang bug看起来像这个clang bug:

This looks like this clang bug:

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

这篇关于当-fno-elide-constructors设置时,clang Xcode 4.4.1 bug吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆