Program Tip

벡터에서 const를 사용하여 요소를 추가 할 수 있지만 이미 추가 된 요소를 수정할 수는 없습니까?

programtip 2020. 12. 5. 10:31
반응형

벡터에서 const를 사용하여 요소를 추가 할 수 있지만 이미 추가 된 요소를 수정할 수는 없습니까?


이 답변에 대한 내 의견 은 constness 및 sorting 문제에 대해 생각하게했습니다. 나는 약간 놀았고이 코드가 다음과 같은 사실로 내 문제를 줄였습니다.

#include <vector>

int main() {
    std::vector <const int> v;  
}

컴파일되지 않습니다-const int의 벡터를 만들 수 없습니다. 분명히 나는 ​​이것을 알고 있었어야했지만 (지적으로 나는 알고 있었지만) 전에는 그런 것을 만들 필요가 없었습니다. 그러나 그것은 나에게 유용한 구조처럼 보이며이 문제를 해결할 방법이 있는지 궁금합니다 . 벡터 (또는 무엇이든)에 무언가를 추가하고 싶지만 추가 된 후에는 변경해서는 안됩니다.

아마도 이것에 대한 당황 스러울 정도로 간단한 해결책이있을 것입니다. 그러나 그것은 제가 이전에 고려한 적이없는 것입니다. 나는 아마 (내가 그것에 대해 또 다른 질문을 볼 수 정렬 언급하지 말았어야 질문의 어려움에 대한). 내 실제 사용 사례는 다음과 같습니다.

vector <const int> v;     // ok (i.e. I want it to be OK)
v.push_back( 42 );        // ok
int n = v[0];             // ok
v[0] = 1;                 // not allowed

글쎄요, C ++ 0x에서는 ...

C ++ 03에는 23.1 [lib.containers.requirements] / 3 단락이 있습니다.

이러한 구성 요소에 저장된 개체 CopyConstructible유형 유형 요구 사항 (20.1.3)과 Assignable유형 의 추가 요구 사항을 충족해야합니다 .

이것이 현재 당신 const intstd::vector.

그러나 C ++ 0X,이 단락이없는 대신 T할 필요가있다 Destructible및 추가 요구 사항에 T예를 들면, 당 표현 지정 v = ustd::vector경우에만 유효 T하다 MoveConstructibleMoveAssignable.

이러한 요구 사항을 올바르게 해석하면 인스턴스화가 가능해야합니다. std::vector<const int>일부 기능이 누락 될 수 있습니다 (원하는 것 같습니다). 반복자 쌍을 생성자에 전달하여 채울 수 있습니다. 나는 그것에 emplace_back()대한 명확한 요구 사항을 찾지 못했지만 잘 작동해야 한다고 생각 합니다 T.

그래도 벡터를 제자리에서 정렬 할 수는 없습니다.


표준 컨테이너에 넣는 유형은 복사 및 할당이 가능해야합니다. auto_ptr그토록 많은 문제 일으키는 이유는 그것이 정상적인 복사 및 할당 의미를 따르지 않기 때문입니다. 당연히, 그 어떤 것도 const할당 할 수 없습니다. 따라서 const표준 용기에 아무것도 붙일 수 없습니다 . 요소가없는 경우 그리고 const, 당신은 되어 변경 할 수있을 것이다.

내가 가능하다고 생각하는 가장 가까운 해결책은 일종의 간접적 인 방향을 사용하는 것입니다. 따라서 const에 대한 포인터를 가질 수 있거나 원하는 값을 보유하는 객체를 가질 수 있지만 값은 객체 내에서 변경할 수 없습니다 ( IntegerJava에서 와 같이 ).

특정 인덱스의 요소를 변경할 수없는 것은 표준 컨테이너가 작동하는 방식에 위배됩니다. 그런 식으로 작업하는 자신을 만들 수 있지만 표준은 그렇지 않습니다. 그리고 배열을 기반으로 {a, b, c}하는 것은 배열 const이 생성 된 후에는 변경할 수 없기 때문에 초기화 구문에 초기화를 맞추지 않는 한 작동하지 않습니다. 따라서 vector클래스는 무엇을하든 const 요소와 함께 작동하지 않을 것입니다.

갖는 const간접의 일종없이 컨테이너에 불과 아주 잘 작동하지 않습니다. 기본적으로 전체 컨테이너를 만들도록 요청 const하고 있습니다. 이미 초기화 된 컨테이너에서 복사하면 할 수 있지만, 어떤 종류의 간접적도없이 상수를 포함하는 컨테이너 (확실히 표준 컨테이너가 아님)는 실제로 가질 수 없습니다. .

편집 : 당신이 찾고있는 것이 대부분 컨테이너를 변경하지 않고 그대로 두지 만 코드의 특정 위치에서 변경할 수있는 경우 대부분의 위치에서 const ref를 사용하고 할 수 있어야하는 코드를 제공합니다 컨테이너 직접 액세스 또는 비 상수 참조를 변경하면 가능합니다.

따라서 const vector<int>&대부분의 장소에서 사용 vector<int>&하고 컨테이너를 변경해야하는 곳에서 사용하거나 코드의 해당 부분에 컨테이너에 대한 직접 액세스 권한을 부여하십시오. 그렇게하면 대부분 변경할 수 없지만 원할 때 변경할 수 있습니다.

반면에 컨테이너에있는 내용은 거의 항상 변경할 수 있지만 특정 요소는 변경하지 않으려면 컨테이너 주위에 래퍼 클래스를 배치하는 것이 좋습니다. 의 경우 vector, 그것을 감싸고 아래 첨자 연산자가 상수가 아닌 참조 대신에 const 참조를 반환하도록 만드십시오. 따라서 템플릿 화 된 버전을 만들었다 고 가정하면 아래 첨자 연산자는 다음과 같습니다.

const T& operator[](size_t i) const
{
    return _container[i];
}

이렇게하면 컨테이너 자체를 업데이트 할 수 있지만 개별 요소는 변경할 수 없습니다. 그리고 모든 함수를 인라인으로 선언하는 한, 래퍼를 사용하는 것이 성능에 큰 영향을 미치지 않아야합니다.


const int 벡터를 만들 수 없으며 가능하더라도 꽤 쓸모가 없습니다. 두 번째 int를 제거하면 그 이후의 모든 것이 하나 아래로 이동합니다. 읽기 : 수정 됨-v [5]가 두 번의 다른 경우에 동일한 값을 갖는다는 것을 보장 할 수 없습니다.

또한 const는 선언 된 후에는 constness를 캐스팅하지 않고 할당 할 수 없습니다. 그리고 그렇게하고 싶다면 왜 처음부터 const를 사용하고 있습니까?


자신 만의 클래스를 작성해야합니다. 확실히 std :: vector를 내부 구현으로 사용할 수 있습니다. 그런 다음 const 인터페이스와 필요한 몇 가지 non-const 함수를 구현하십시오.


이것이 모든 요구 사항을 충족하지는 못하더라도 (정렬 가능) 상수 벡터를 사용해보십시오.

int values[] = {1, 3, 5, 2, 4, 6};
const std::vector<int> IDs(values, values + sizeof(values));

하지만 std::list. 목록을 사용하면 값을 변경할 필요가 없으며 링크 만 변경할 수 있습니다. 정렬은 링크의 순서를 변경하여 수행됩니다.

당신은 약간의 두뇌 능력을 소비하고 자신의 것을 써야 할 수도 있습니다. :-(


모든 const 객체를 표준 배열에 넣을 것입니다.
그런 다음 포인터 벡터를 배열에 사용합니다.
객체와 건초 더미를 역 참조하지 않아도되는 작은 유틸리티 클래스입니다.

#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>


class XPointer
{
    public:
        XPointer(int const& data)
            : m_data(&data)
        {}

    operator int const&() const
    {
        return *m_data;
    }

    private:
        int const*  m_data;

};

int const               data[]    =  { 15, 17, 22, 100, 3, 4};

std::vector<XPointer>   sorted(data,data+6);


int main()
{
    std::sort(sorted.begin(), sorted.end());
    std::copy(sorted.begin(), sorted.end(), std::ostream_iterator<int>(std::cout, ", "));
    int x   = sorted[1];
}

I'm with Noah: wrap the vector with a class that exposes only what you want to allow.

If you don't need to dynamically add objects to the vector, consider std::tr1::array.


If constness is important to you in this instance I think you probably want to work with immutable types all the way up. Conceptually you'll have a fixed size, const array of const ints. Any time you need to change it (e.g. to add or remove elements, or to sort) you'll need to make a copy of the array with the operation performed and use that instead. While this is very natural in a functional language it doesn't seem quite "right" in C++. getting efficient implementations of sort, for example, could be tricky - but you don't say what you're performance requirements are. Whether you consider this route as being worth it from a performance/ custom code perspective or not I believe it is the correct approach.

After that holding the values by non-const pointer/ smart pointer is probably the best (but has its own overhead, of course).


I've been thinking a bit on this issue and it seems that you requirement is off.

You don't want to add immutable values to your vector:

std::vector<const int> vec = /**/;
std::vector<const int>::const_iterator first = vec.begin();

std::sort(vec.begin(), vec.end());

assert(*vec.begin() == *first); // false, even though `const int`

What you really want is your vector to hold a constant collection of values, in a modifiable order, which cannot be expressed by the std::vector<const int> syntax even if it worked.

I am afraid that it's an extremely specified task that would require a dedicated class.


It is true that Assignable is one of the standard requirements for vector element type and const int is not assignable. However, I would expect that in a well-thought-through implementation the compilation should fail only if the code explicitly relies on assignment. For std::vector that would be insert and erase, for example.

In reality, in many implementations the compilation fails even if you are not using these methods. For example, Comeau fails to compile the plain std::vector<const int> a; because the corresponding specialization of std::allocator fails to compile. It reports no immediate problems with std::vector itself.

I believe it is a valid problem. The library-provided implementation std::allocator is supposed to fail if the type parameter is const-qualified. (I wonder if it is possible to make a custom implementation of std::allocator to force the whole thing to compile.) (It would also be interesting to know how VS manages to compile it) Again, with Comeau std::vector<const int> fails to compiler for the very same reasons std::allocator<const int> fails to compile, and, according to the specification of std::allocator it must fail to compile.

Of course, in any case any implementation has the right to fail to compile std::vector<const int> since it is allowed to fail by the language specification.


Using just an unspecialized vector, this can't be done. Sorting is done by using assignment. So the same code that makes this possible:

sort(v.begin(), v.end());

...also makes this possible:

v[1] = 123;


You could derive a class const_vector from std::vector that overloads any method that returns a reference, and make it return a const reference instead. To do your sort, downcast back to std::vector.


std::vector of constant object will probably fail to compile due to Assignable requirement, as constant object can not be assigned. The same is true for Move Assignment also. This is also the problem I frequently face when working with a vector based map such as boost flat_map or Loki AssocVector. As it has internal implementation std::vector<std::pair<const Key,Value> > . Thus it is almost impossible to follow const key requirement of map, which can be easily implemented for any node based map.

However it can be looked, whether std::vector<const T> means the vector should store a const T typed object, or it merely needs to return a non-mutable interface while accessing. In that case, an implementation of std::vector<const T> is possible which follows Assignable/Move Assignable requirement as it stores object of type T rather than const T. The standard typedefs and allocator type need to be modified little to support standard requirements.Though to support such for a vector_map or flat_map, one probably needs considerable change in std::pair interface as it exposes the member variables first & second directly.


Compilation fails because push_back() (for instance) is basically

underlying_array[size()] = passed_value;

where both operand are T&. If T is const X that can't work.

Having const elements seem right in principle but in practice it's unnatural, and the specifications don't say it should be supported, so it's not there. At least not in the stdlib (because then, it would be in vector).

참고URL : https://stackoverflow.com/questions/2759350/can-i-use-const-in-vectors-to-allow-adding-elements-but-not-modifications-to-th

반응형