값으로 반환 할 수있는 메모리 효율적인 VLA 유형을 만들 수 있습니까?

테일러

C ++에서 VLA (스택 할당, 가변 크기)처럼 작동하고 함수에서 반환 될 수도 있고 선형 할당 자처럼 메모리를 낭비하지 않는 유형을 생성 할 수 있는지 궁금합니다.

다음과 같이 사용할 수 있습니다.

// Fibonacci sequence
stack_array<int> fib(size_t n) {

  stack_array<int> f(n);
  f[0] = 0;
  f[1] = 1;
  for(size_t i=2;i<n;++i) {
    f[i] = f[i-1] + f[i-2];
  }

  return f;
}

std::vector힙 할당과 함께 가변 크기의 항목 (일반적으로 사용 )을 반환하기 때문에 유용합니다 . 힙 할당이 허용되지 않는 실시간 컨텍스트에서이 작업을 수행 할 수도 있습니다. 오디오 버퍼에 대한 기능적 스타일 프로그래밍. 하지만 대체로 이것은 무엇이 가능한지 알아보기위한 지적 연습입니다.

std::allocator선형 할당을 수행하여 실시간 제약 조건을 충족하고 사소하지 않은 유형을 쉽게 지원하는를 작성할 수 있다는 것을 알고 있지만 이것은 메모리 낭비의 단점이 있습니다. 더 잘할 수 있을지 궁금합니다.

이를 더 구체적으로 만들기 위해 다음이 있다고 가정합니다.

thread_local arena myArena; // I don't want to have to pass this around!

std::vector<float> f() {
   return std::vector<float, arena>(64, myArena);
}

std::vector<float> g() {
   return std::vector<float, arena>(64, myArena);
}

void main() {

   {
       auto a = f();
   }

   {
       auto b = g();
   }

   // At this point, we still have 128*sizeof(float) allocated.
   // You might say to use multiple arenas, but that might not
   // be easy.
}

이제 함수에서 반환하지 않으면 LIFO 생성 / 파괴 순서가 보장된다는 것을 알고 있습니다 (RAII에 필요함). 컨테이너에 제약 조건을 적용하여 LIFO 순서를 보장하면서 함수에서 반환 할 수 있는지 궁금합니다.

여기에 별도의 thread_local스택을 사용하여 구현하려는 시도가 있지만 구성 및 파괴 순서가 불변을 약간 혼란스럽게 유지하도록 보장하기 때문에 실제로 올바른지 모르겠습니다.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <iostream>
#include <type_traits>

// Big stack.
static size_t stackSize = 1024*1024*10;
static thread_local uint8_t* start = nullptr;
static thread_local uint8_t* stack = nullptr;

// An array with simple stack based allocation.
// Size is fixed on creation.
//
// I'm assuming this is difficult with std::vector
// and a custom allocator because it can grow.
// 
// T must be trivial for now
template<class T>
class stack_array {

    size_t _size;
    T* ptr;

public:

    stack_array(size_t size) : _size(size) {
        static_assert(std::is_trivial<T>::value);
        if(stack == nullptr) {
            start = stack = (uint8_t*) malloc(stackSize);
        }
        ptr = (T*) stack;
        stack += size*sizeof(T);
        assert(stack < start + stackSize);
        printf("ctor %p, stack %d\n", (void*) this, int(stack - start));
    }

    // I think the copy constructor violates our stack
    // nesting property, since the lifetimes overlap.
    stack_array(const stack_array&) = delete;

    ~stack_array() {
        stack -= _size*sizeof(T);
        printf("dtor %p, stack %d\n", (void*) this, int(stack - start));
    }

    stack_array& operator=(const stack_array& a) {
        printf("assign\n");
        assert(_size == a._size);
        for(size_t i=0;i<_size;++i) {
            ptr[i] = a.ptr[i];
        }
        return *this;
    }

    // Is this actually correct?
    stack_array(stack_array&& other) {
        printf("move\n");
        ptr = other.ptr;
        _size = other._size;
        other._size = 0;
    }

    T& operator[](size_t i) { assert(i < _size); return ptr[i]; }
    const T& operator[](size_t i) const { assert(i < _size); return ptr[i]; }

    size_t size() const { return _size; }
};

// Fibonacci sequence
stack_array<int> fib(size_t n) {

    stack_array<int> f(n);
    f[0] = 0;
    f[1] = 1;
    for(size_t i=2;i<n;++i) {
        f[i] = f[i-1] + f[i-2];
    }

    return f;
}

template<class T, class F>
void foreach(const stack_array<T> &a, F f) {
    for(size_t i=0;i<a.size();++i) {
        f(a[i]);
    }
}

template<class T, class F>
auto map(const stack_array<T> &a, F f) {
    stack_array< decltype(f(T())) > r(a.size());
    for(size_t i=0;i<a.size();++i) {
        r[i] = f(a[i]);
    }
    return r;
}

template<class T, class F>
auto filter(const stack_array<T> &a, F f) {
    stack_array<int> b(a.size());
    size_t n = 0;
    for(size_t i=0;i<a.size();++i) {
        if(f(a[i])) {
            b[n++] = i;
        }
    }
    stack_array<T> r(n);
    for(size_t i=0;i<n;++i) {
        r[i] = a[b[i]];
    }
    return r;
}

template<class T> void printArray(const stack_array<T> &a) {
    foreach(a, [](T t){ std::cout << t << std::endl;});
}

int main(int argc, char* argv[]) {

    {
        stack_array<int> a = fib(20);
        printArray(a);
        printArray(map(a, [](int i) { return i+1; }));
        printArray(filter(a, [](int i) { return i%2; }));

        stack_array<int> b(a.size());
        b = a;
    }
    assert(stack == start);

}
나노 패러 드

스택 기반 접근 방식을 간략히 살펴보면 자체 작은 개인 힙에서 작동하는 힙 기반 할당 자에 지나지 않지만 엄격한 제한이있어 할당이 엄격하게 LIFO 순서로 수행되지 않으면 오작동합니다. 이 속도에서는 동일한 할당 메커니즘을 유지하면서 실제로 중요하지 않은 유형을 지원하도록 확장하는 것을 고려할 수 있습니다.

즉, 정상적인 사용 하에서는 전제 조건을 유지하지 않는 것 같습니다. 그때 filter구성 하지만 겉보기에는 오래 지속되는 것 같습니다 (액터 및 dtor에서 "스택"의 비트를 수동으로 중독 및 제거하여 ASAN에서 발견).brrb

메모리가 너무 빡빡하지 않으면 아레나 할당 자 사용을 고려할 수 있습니다. (사용자에 대한 명시적인 요구 사항으로 또는 참조 계산을 통해) 할당 된 모든 할당보다 오래 지속되는 작은 경기장을 유지할 수 있습니다.

또한 호출자에 스택 기반 배열을 할당하고 포인터 / 참조를 전달하는 것과 같이 값을 반환하는 더 전통적인 방법을 고려할 수도 있습니다. 적어도 오디오 애플리케이션의 경우 고정 길이 버퍼도 적합 할 수 있습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

다른 유형을 다형 적으로 반환 할 수있는 C ++에서 팩토리 메서드를 만드는 방법은 무엇입니까?

이것을 함수 또는 더 효율적인 것으로 만들 수있는 방법이 있습니까?

무기한 증가 할 수있는 동적 목록 속성을 만드는 메모리 효율적인 방법

바인딩이있는이 일반적인 메소드가 어떤 유형을 반환 할 수 있습니까?

메서드 체이닝에 적합한 구현 유형을 Groovy 특성으로 반환 할 수 있습니까?

인수를 기반으로 Rust 함수 또는 특성 메서드의 반환 유형을 계산할 수 있습니까?

여러 UNION이 모두 동일한 조인을 수행 할 때 더 효율적으로 만드는 방법이 있습니까?

유형만을 기반으로 sqlcontext 암시 적 인코더를 생성하는 스칼라 메서드를 어떻게 만들 수 있습니까?

promiess가 아닌 값으로 배열을 반환하는 promise를 어떻게 (효율적으로) 연결할 수 있습니까?

malloc에 의해 반환 된 메모리 주소는 항상 다른 유형에 대한 포인터로 교환 할 수 있습니까?

char *에 메모리를 할당 할 수 있지만 const char *로 반환 할 수 있습니까?

값이 유효한 범위 내에 만있을 수있는 유형을 어떻게 만들 수 있습니까?

close 메소드에서 javaFX의 변수를 반환 할 수 있습니까? 이를 수행하는 더 효율적인 방법이 있습니까?

이 vbnet 코드를 더 효율적으로 만들기 위해 어떻게 반복을 사용할 수 있습니까?

SQL Subquery는 하나의 값만 반환합니다. 어떻게이 코드를 효율적으로 만들 수 있습니까?

Django - 템플릿에서 반복할 수 있는 효율적인 방법으로 최신 관련 모델을 얻는 방법은 무엇입니까?

Visual C ++에서 스택 메모리를 동적으로 할당 할 수없는 이유는 무엇입니까? 하지만 gcc는 할 수 있습니다

입력이 최대 1000000000이 될 수 있다는 점을 감안할 때 더 많은 시간과 메모리 효율적인 프로그램을 어떻게 작성할 수 있습니까? (m과 n 사이의 모든 소수 인쇄)

Kotlin 다형성 - 수신 인수는 유형을 재정의할 수 없지만 반환 인수는 재정의할 수 있습니까?

색인을 사용하여이 요청을보다 효율적으로 만들 수 있습니까?

희소 파일로 losetup을 효율적으로 만들 수 있습니까?

이 SQL 쿼리를 더 효율적으로 만들 수 있습니까?

이 쿼리를 어떻게 더 효율적으로 만들 수 있습니까?

합계가있는 여러 조인을 기반으로 쿼리를 만들 수 있습니까?

(Lisp) 이것을 더 효율적으로 만들 수 있습니까?

Mockito는 메서드 호출시 값을 기반으로 매개 변수를 확인할 수 있습니까?

반환 유형으로 Page <Object>가있을 때 Spring Boot에서 Testing을 어떻게 만들 수 있습니까?

UIView 또는 UIButton을 매개변수로 사용할 수 있는 일반 함수를 만들 수 있습니까?

이 알고리즘을 퍼즐에 더 효율적으로 만들 수있는 방법은 무엇입니까?