ProgramingTip

C ++ : 배열 용 생성자 이니셜 라이저

bestdevel 2020. 11. 24. 18:51
반응형

C ++ : 배열 용 생성자 이니셜 라이저


뇌 경련이 있습니다. C ++에서 배열을 선택해야합니까?

배열이 아닌 예 :

struct Foo { Foo(int x) { /* ... */  } };

struct Bar { 
     Foo foo;

     Bar() : foo(4) {}
};

배열 예 :

struct Foo { Foo(int x) { /* ... */  } };

struct Baz { 
     Foo foo[3];

     // ??? I know the following syntax is wrong, but what's correct?
     Baz() : foo[0](4), foo[1](5), foo[2](6) {}
};

편집 : 미친 해결 방법 아이디어는 감사하지만 제 경우에는 도움이되지 않습니다. std :: vector 및 기타 STL 구문을 사용할 수없는 해결 프로세서에서 작업 중이며 명확한 해결 방법은 기본 init()생성 생성 생성 시간 이후에 호출 할 수 있는 명시 메서드를 호출 할 수 있습니다. 이니셜 라이저를 전혀 사용할 수 없습니다. (이것은 내가 Java의 final키워드 + 생성자와의 유연성에 의해 망 쳐진 경우 중 하나입니다 .)


방법이 없다. 배열 멤버에 대한 기본 생성자가 필요하며 나중에 호출되어 생성자에서 원하는 초기화를 수행 할 수 있습니다.


C ++ 11에 대한이 질문을 업데이트하기 위해 이제는 가능하고 매우 자연 스럽습니다.

struct Foo { Foo(int x) { /* ... */  } };

struct Baz { 
     Foo foo[3];

     Baz() : foo{{4}, {5}, {6}} { }
};

더 간결하게하기 위해 단지 중괄호를 생략 할 수도 있습니다.

struct Baz { 
     Foo foo[3];

     Baz() : foo{4, 5, 6} { }
};

다차원 배열로 쉽게 확장 할 수 있습니다.

struct Baz {
    Foo foo[3][2];

    Baz() : foo{1, 2, 3, 4, 5, 6} { }
};

지금은 배열 멤버에 대한 초기화 목록을 사용할 수 없습니다. 당신은 열심히 일하고 있습니다.

class Baz {
    Foo foo[3];

    Baz() {
        foo[0] = Foo(4);
        foo[1] = Foo(5);
        foo[2] = Foo(6);
    }
};

C ++ 0x에서는 다음과 같이 사용할 수 있습니다.

class Baz {
    Foo foo[3];

    Baz() : foo({4, 5, 6}) {}
};

불행히도 C ++ 0x까지 배열 멤버를 초기화하는 방법이 없습니다.

std :: vector를 사용하고 생성자 본문에서 Foo 인스턴스를 push_back 할 수 있습니다.

Foo에 기본 생성 기능을 제공 할 수 있습니다 (비공개 일 수 있고 Baz를 친구로 만들 수 있음).

당신은 배열 개체를 사용할 수 있습니다. 복사 가능 (부스트 또는 표준 : TR1)을 정적 배열에서 초기화 :

#include <boost/array.hpp>

struct Baz {

    boost::array<Foo, 3> foo;
    static boost::array<Foo, 3> initFoo;
    Baz() : foo(initFoo)
    {

    }
};

boost::array<Foo, 3> Baz::initFoo = { 4, 5, 6 };

예를 들어 (와 유사 ) 라는 이름의 함수에 템플릿 전문화 와 함께 C ++ 0x auto 키워드를 사용할 수 있습니다 . 인수가 1 또는 2 인 경우 변수다음 과 같이 작성할 수 있습니다.boost::make_array()make_pair()N

namespace boost
{
/*! Construct Array from @p a. */
template <typename T>
boost::array<T,1> make_array(const T & a)
{
    return boost::array<T,2> ({{ a }});
}
/*! Construct Array from @p a, @p b. */
template <typename T>
boost::array<T,2> make_array(const T & a, const T & b)
{
    return boost::array<T,2> ({{ a, b }});
}
}

변형 B

namespace boost {
/*! Construct Array from @p a. */
template <typename T>
boost::array<T,1> make_array(const T & a)
{
    boost::array<T,1> x;
    x[0] = a;
    return x;
}
/*! Construct Array from @p a, @p b. */
template <typename T>
boost::array<T,2> make_array(const T & a, const T & b)
{
    boost::array<T,2> x;
    x[0] = a;
    x[1] = b;
    return x;
}
}

와 GCC-4.6 -std=gnu++0x-O3생성 동일한 바이너리 코드 를 들어

auto x = boost::make_array(1,2);

모두 사용 B 를가에서는 없다

boost::array<int, 2> x = {{1,2}};

들어를 user-정의 유형 (UDT)하지만,에 변형 B 결과를의 별도의 복사 생성자 , 일반적으로 느린 것을 아래로, 그리고해야하므로 피해야한다.

boost::make_array다음 경우와 같이 명시 적 문자 배열 리터럴로 호출 할 때 오류 발생합니다.

auto x = boost::make_array("a","b");

const char*리터럴은 사용시 기만적있으므로 좋은 생각 합니다.

가변 템플릿 4.5 보낸 GCC 가능은, 상기 각각의 모든 템플릿 특수화 보일러 플레이트N(A) 내로 하나의 템플릿 정의boost::make_array()정의

/*! Construct Array from @p a, @p b. */
template <typename T, typename ... R>
boost::array<T,1+sizeof...(R)> make_array(T a, const R & ... b)
{
    return boost::array<T,1+sizeof...(R)>({{ a, b... }});
}

이것은 우리가 예상 한대로 거의 작동합니다. 첫 번째 인수는 boost::array템플릿 인수를 결정 T하고 다른 모든 인수는 변환 T됩니다. 어떤 경우에는 어떤 경우에도 사용할 수 있습니다.

아마도 boost::make_array()Boost Libraries로 가야할까요?


이것은 작동하는 것처럼 보이지만 그것이 옳다고 확신하지 않습니다.

#include <iostream>

struct Foo { int x; Foo(int x): x(x) { } };

struct Baz { 
     Foo foo[3];

    static int bar[3];
     // Hmm...
     Baz() : foo(bar) {}
};

int Baz::bar[3] = {4, 5, 6};

int main() {
    Baz z;
    std::cout << z.foo[1].x << "\n";
}

다수 :

$ make arrayinit -B CXXFLAGS=-pedantic && ./arrayinit
g++ -pedantic    arrayinit.cpp   -o arrayinit
5

주의 사항.

편집 : 아니요, Comeau는 거부합니다.

또 다른 편집 : 이것은 내부에 속임수이며, 멤버 별 배열 초기화를 다른 위치로 푸시합니다. 따라서 Foo에 기본 생성자가 std::vector필요한 경우 절대 최소값을 직접 구현할 수 있습니다.

#include <iostream>

struct Foo { 
    int x; 
    Foo(int x): x(x) { }; 
    Foo(){}
};

// very stripped-down replacement for vector
struct Three { 
    Foo data[3]; 
    Three(int d0, int d1, int d2) {
        data[0] = d0;
        data[1] = d1;
        data[2] = d2;
    }
    Foo &operator[](int idx) { return data[idx]; }
    const Foo &operator[](int idx) const { return data[idx]; }
};

struct Baz { 
    Three foo;

    static Three bar;
    // construct foo using the copy ctor of Three with bar as parameter.
    Baz() : foo(bar) {}
    // or get rid of "bar" entirely and do this
    Baz(bool) : foo(4,5,6) {}
};

Three Baz::bar(4,5,6);

int main() {
    Baz z;
    std::cout << z.foo[1].x << "\n";
}

z.foo실제로는 배열이 행렬, 벡터가하는 것처럼. 세에 추가 begin()하고 end()기능 현관하는 [해석] 간단합니다.


배열에 개체를 만들 때 기본 생성자 만 호출 할 수 있습니다.


배열이 클래스의 데이터 멤버 인 특정 경우 에는 현재 버전의 언어로 초기화 수 없습니다 . 구문 대한 구문이 없습니다. 배열 요소에 대한 기본 생성 기능을 제공하거나 std::vector.

이니셜 라이저로 독립형 배열을 초기화 할 수 있습니다.

Foo foo[3] = { 4, 5, 6 };

그러나 불행히도 생성자 이니셜 라이저 목록에 해당하는 구문이 없습니다.


이 구성에서 사용되는 배열 구문은 없습니다. 다음과 같은 라인을 따라 수행하려는 작업을 수행 할 수 있습니다.

Bar::Bar()
{
    static const int inits [] = {4,5,6};
    static const size_t numInits = sizeof(inits)/sizeof(inits[0]);
    std::copy(&inits[0],&inits[numInits],foo);  // be careful that there are enough slots in foo
}

...하지만 Foo에 기본 생성자를 제공해야합니다.


뒤틀린 마음의 아이디어 :

class mytwistedclass{
static std::vector<int> initVector;
mytwistedclass()
{
    //initialise with initVector[0] and then delete it :-)
}

};

이제 initVector개체를 인스턴스화하기 전에 원하는 것으로 설정하십시오 . 그런 다음 개체가 매개 변수로 초기화됩니다.


할 수 있지만 예쁘지 않습니다.

#include <iostream>

class A {
    int mvalue;
public:
    A(int value) : mvalue(value) {}
    int value() { return mvalue; }
};

class B {
    // TODO: hack that respects alignment of A.. maybe C++14's alignof?
    char _hack[sizeof(A[3])];
    A* marr;
public:
    B() : marr(reinterpret_cast<A*>(_hack)) {
        new (&marr[0]) A(5);
        new (&marr[1]) A(6);
        new (&marr[2]) A(7);
    }

    A* arr() { return marr; }
};

int main(int argc, char** argv) {
    B b;
    A* arr = b.arr();
    std::cout << arr[0].value() << " " << arr[1].value() << " " << arr[2].value() << "\n";
    return 0;
}

이것을 코드에 넣으면 아주 좋은 이유가 있기를 바랍니다.


이것은 당신의 참고를위한 나의 해결책입니다 :

struct Foo
{
    Foo(){}//used to make compiler happy!
    Foo(int x){/*...*/}
};

struct Bar
{
    Foo foo[3];

    Bar()
    {
        //initialize foo array here:
        for(int i=0;i<3;++i)
        {
            foo[i]=Foo(4+i);
        }
    }
};

Visual Studio 2012 이상에서는 다음과 같이 할 수 있습니다.

struct Foo { Foo(int x) { /* ... */  } };

struct Baz { 
     Foo foo[3];

     Baz() : foo() { }
};

class C
{
   static const int myARRAY[10];  // only declaration !!!

   public:
   C(){}
   }

const int C::myARRAY[10]={0,1,2,3,4,5,6,7,8,9};  // here is definition

int main(void)
{
   C myObj;
   }

참고 URL : https://stackoverflow.com/questions/2409819/c-constructor-initializer-for-arrays

반응형