문제

800x800 크기의 2D int 배열을 만들어야 합니다.하지만 그렇게 하면 스택 오버플로가 발생합니다(하하).

저는 C++을 처음 접하는데 벡터의 벡터 같은 작업을 해야 합니까?그리고 2D 배열을 클래스로 캡슐화합니까?

특히 이 배열은 그래픽 프로그램의 zbuffer입니다.화면의 모든 픽셀에 대해 z 값을 저장해야 합니다(따라서 800x800의 큰 크기).

감사해요!

도움이 되었습니까?

해결책

약 2.5MB가 필요하므로 힙을 사용하는 것만으로도 충분합니다.크기를 조정해야 하는 경우가 아니면 벡터는 필요하지 않습니다.보다 C++ FAQ 라이트 "2D" 힙 배열 사용의 예는 다음과 같습니다.

int *array = new int[800*800];

(잊지 마세요. delete[] 끝나면 하세요.)

다른 팁

지금까지 모든 게시물은 프로그래머에게 메모리 관리를 맡겼습니다.이는 피할 수 있고 피해야 합니다.ReaperUnreal은 배열이 아닌 벡터를 사용하고 치수 템플릿 매개변수를 만들고 액세스 기능을 변경한다는 점을 제외하면 제가 하려는 작업과 매우 유사합니다. 아, IMNSHO가 약간 정리하면 됩니다.

template <class T, size_t W, size_t H>
class Array2D
{
public:
    const int width = W;
    const int height = H;
    typedef typename T type;

    Array2D()
        : buffer(width*height)
    {
    }

    inline type& at(unsigned int x, unsigned int y)
    {
        return buffer[y*width + x];
    }

    inline const type& at(unsigned int x, unsigned int y) const
    {
        return buffer[y*width + x];
    }

private:
    std::vector<T> buffer;
};

이제 이 2차원 배열을 스택에 잘 할당할 수 있습니다.

void foo()
{
    Array2D<int, 800, 800> zbuffer;

    // Do something with zbuffer...
}

이게 도움이 되길 바란다!

편집하다:에서 어레이 사양을 제거했습니다. Array2D::buffer.그것을 잡아준 Andreas에게 감사드립니다!

그러나 Kevin의 예는 좋습니다.

std::vector<T> buffer[width * height];

해야한다

std::vector<T> buffer;

조금 확장하면 at() 함수 대신 연산자 오버로드를 추가할 수도 있습니다.

const T &operator()(int x, int y) const
{
  return buffer[y * width + x];
}

그리고

T &operator()(int x, int y)
{
  return buffer[y * width + x];
}

예:

int main()
{
  Array2D<int, 800, 800> a;
  a(10, 10) = 50;
  std::cout << "A(10, 10)=" << a(10, 10) << std::endl;
  return 0;
}

벡터로 구성된 벡터를 만들 수 있지만 그렇게 하면 약간의 오버헤드가 발생합니다.z-버퍼의 경우 보다 일반적인 방법은 800*800=640000 크기의 배열을 만드는 것입니다.

const int width = 800;
const int height = 800;
unsigned int* z_buffer = new unsigned int[width*height];

그런 다음 다음과 같이 픽셀에 액세스합니다.

unsigned int z = z_buffer[y*width+x];

800*800의 단일 차원 배열을 만들 수 있습니다.800개의 개별 벡터를 할당하는 것보다 이와 같은 단일 할당을 사용하는 것이 더 효율적일 수 있습니다.

int *ary=new int[800*800];

그런 다음 이를 2D 배열처럼 작동하는 클래스에 캡슐화할 수 있습니다.

class _2DArray
{
  public:
  int *operator[](const size_t &idx)
  {
    return &ary[idx*800];
  }
  const int *operator[](const size_t &idx) const
  {
    return &ary[idx*800];
  }
};

여기에 표시된 추상화에는 많은 구멍이 있습니다. 예를 들어 "행"의 끝을 지나서 액세스하면 어떻게 될까요?"Effective C++"라는 책에는 C++로 좋은 다차원 배열을 작성하는 방법이 꽤 잘 설명되어 있습니다.

당신이 할 수 있는 한 가지는 VC를 사용하여 스택 크기를 변경하는 것입니다(정말로 스택에 배열을 원하는 경우). 이를 수행하는 플래그는 [/F](http://msdn.microsoft.com/en-us/library/tdkhxaks(VS.80).aspx).

그러나 아마도 당신이 원하는 해결책은 메모리를 스택이 아닌 힙에 두는 것입니다. vector ~의 vectors.

다음 줄은 vector 800개 요소 중 각 요소는 vector 800개 중 ints를 사용하면 메모리를 수동으로 관리할 필요가 없습니다.

std::vector<std::vector<int> > arr(800, std::vector<int>(800));

두 개의 닫는 꺾쇠 괄호 사이의 공백(> >) 이는 오른쪽 시프트 연산자(더 이상 필요하지 않음)와의 구분을 위해 필요합니다. C++0x).

아니면 다음과 같이 시도해 볼 수도 있습니다.

boost::shared_array<int> zbuffer(new int[width*height]);

당신은 여전히 ​​이 작업을 수행할 수 있어야 합니다:

++zbuffer[0];

더 이상 메모리 관리에 대해 걱정할 필요가 없고, 처리할 사용자 정의 클래스도 없으며, 사용하기 쉽습니다.

C와 같은 수행 방법이 있습니다.

const int xwidth = 800;
const int ywidth = 800;
int* array = (int*) new int[xwidth * ywidth];
// Check array is not NULL here and handle the allocation error if it is
// Then do stuff with the array, such as zero initialize it
for(int x = 0; x < xwidth; ++x)
{
    for(int y = 0; y < ywidth; ++y)
    {
         array[y * xwidth + x] = 0;
    }
}
// Just use array[y * xwidth + x] when you want to access your class.

// When you're done with it, free the memory you allocated with
delete[] array;

당신은 y * xwidth + x 쉬운 get 및 set 메소드를 사용하여 클래스 내에서(아마도 [] 더 고급 C++에 들어가고 싶다면 연산자를 사용하세요).C++로 막 시작하고 n차원 배열에 대해 재사용 가능한 전체 클래스 템플릿을 생성하기 시작하지 않는다면 천천히 시작하는 것이 좋습니다. 시작할 때 혼란스러울 것입니다.

그래픽 작업을 시작하자마자 추가 클래스 호출로 인한 오버헤드로 인해 코드 속도가 느려질 수 있다는 것을 알게 될 것입니다.그러나 애플리케이션이 충분히 빠르지 않을 때까지는 걱정하지 마십시오. 처음에 불필요하게 복잡하여 사용하기 어렵게 만드는 대신 시간이 손실된 위치를 표시하도록 프로파일링할 수 있습니다.

저는 C++ 라이트 FAQ가 이와 같은 정보를 제공하는 데 유용하다는 것을 알았습니다.특히 귀하의 질문에 대한 답변은 다음과 같습니다.

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.16

정적 저장소(파일 범위 내)에 배열을 할당하거나 추가할 수 있습니다. static 함수 범위의 한정자), 인스턴스가 하나만 필요한 경우.

int array[800][800];

void fn()
{
    static int array[800][800];
}

이렇게 하면 스택으로 이동하지 않으며 동적 메모리를 처리할 필요가 없습니다.

글쎄, Niall Ryan이 시작한 것을 기반으로 성능이 문제인 경우 수학을 최적화하고 이를 클래스에 캡슐화하여 한 단계 더 나아갈 수 있습니다.

그럼 우리는 약간의 수학부터 시작하겠습니다.800은 2의 거듭제곱으로 다음과 같이 쓸 수 있다는 점을 기억하세요.

800 = 512 + 256 + 32 = 2^5 + 2^8 + 2^9

따라서 주소 지정 기능을 다음과 같이 작성할 수 있습니다.

int index = y << 9 + y << 8 + y << 5 + x;

따라서 모든 것을 좋은 클래스로 캡슐화하면 다음과 같은 결과를 얻습니다.

class ZBuffer
{
public:
    const int width = 800;
    const int height = 800;

    ZBuffer()
    {
        for(unsigned int i = 0, *pBuff = zbuff; i < width * height; i++, pBuff++)
            *pBuff = 0;
    }

    inline unsigned int getZAt(unsigned int x, unsigned int y)
    {
        return *(zbuff + y << 9 + y << 8 + y << 5 + x);
    }

    inline unsigned int setZAt(unsigned int x, unsigned int y, unsigned int z)
    {
        *(zbuff + y << 9 + y << 8 + y << 5 + x) = z;
    }
private:
    unsigned int zbuff[width * height];
};
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top