상수 클래스 멤버, 할당 연산자 및 QList (Constant class members, assignment operator and QList)


문제 설명

상수 클래스 멤버, 할당 연산자 및 QList (Constant class members, assignment operator and QList)

제 말이 맞다면 확인하고 더 나은 솔루션이 있는지 알려주세요:

int const width;와 같은 상수 멤버가 있는 객체는 컴파일러에 의해 암시적으로 생성되는 합성 할당 연산자입니다. 그러나 QList(그리고 std::list도 마찬가지입니다)에는 작업 할당 연산자가 필요합니다. 따라서 상수 멤버와 QList가 있는 객체를 사용하려면 세 가지 가능성이 있습니다.

  1. 상수 멤버를 사용하지 마십시오. (해결 방법이 아님)
  2. 나만의 할당 연산자를 구현합니다.
  3. 할당 연산자가 필요하지 않은 다른 컨테이너를 사용합니다.

맞나요? 다른 우아한 솔루션이 있습니까?

또한 다음 작업을 수행할 수 있는지 궁금합니다.< /p>

  • (4) 컴파일러가 상수 멤버를 처리하는 할당 연산자를 만들도록 강제합니다! (이것이 왜 그렇게 큰 문제인지 이해가 되지 않습니다. 왜 연산자가 내부적으로 초기화 목록을 사용할 만큼 충분히 지능적이지 않습니까? 아니면 제가 뭔가를 놓치고 있습니까?)
  • (5) QList에 목록에서 할당 작업을 사용합니다.

편집: 이 클래스의 개체를 직접 할당하지 않습니다. 복사 생성자 또는 오버로드된 생성자에 의해서만 생성됩니다. 따라서 할당 연산자는 나 자신이 아닌 컨테이너에서만 필요합니다.

EDIT2: 이것은 내가 만든 할당 연산자입니다. 그것이 맞는지 확실하지 않습니다. Cell에는 두 개의 매개변수 생성자가 있습니다. 이 매개변수는 초기화 목록이 있는 두 개의 상수 멤버를 설정합니다.

Cell& Cell::operator=(Cell const& other)
{
 if (this != &other) {
  Cell* newCell = new Cell(other.column(), other.row());
  return *newCell;
 }
 return *this;
}

EDIT3: 거의 동일한 질문으로 이 스레드를 찾았습니다. C++: const 클래스 구성원과 관련된 STL 문제 모든 답변이 결합됨 내 질문에 함께 답했습니다.


참조 솔루션

방법 1:

You are probably a newcomer to C++ and expect it to behave like Python, Java or C#.

It is quite common to put immutable Java objects into collections. This works because in Java, you do not really put Java objects into collections but merely Java references which refer to Java objects. To be even more precise, a collection internally consists of Java reference variables, and assigning to these Java reference variables does not affect the referenced Java objects at all. They don't even notice.

I deliberately said "Java object", "Java reference" and "Java variable", because the terms "object", "reference" and "variable" have completely different meanings in C++. If you want mutable T variables, you want mutable T objects, because variables and objects are basically the same thing in C++:

A variable is introduced by the declaration of an object. The variable's name denotes the object.

In C++, variables do not contain objects ‑‑ they are objects. Assigning to a variable means changing the object (by calling the member function operator=). There is no way around it. If you have an immutable object, then the assignment a = b cannot possibly work without explicitly undermining the type system, and if you do that, then you have effectively lied to your clients about the object being immutable. Making a promise and then deliberately breaking it is rather pointless, isn't it?

Of course you could simply simulate the Java way: use a collection of pointers to immutable objects. Whether or not this is an effective solution depends on what your objects really represent. But just because this works well in Java does not mean it works well in C++. There is no such thing as an immutable value object pattern in C++. It is a good idea in Java and a terrible idea in C++.

By the way, your assignment operator is completely non‑idiomatic and leaks memory. If you are serious about learning C++, you should read one of these books.

방법 2:

(4) is not an option. The implicitly declared copy assignment operator assigns each member of the right‑hand side object to the same member of the left‑hand side object.

The compiler can't implicitly generate a copy assignment operator for a class that has const‑qualified data members for the same reason that this is invalid:

const int i = 1;
i = 2;

(2) is problematic since you have to overcome this same issue somehow.

(1) is the obvious solution; if your class type has const‑qualified data members, it is not assignable and assignment doesn't make much sense. Why do you say that this is not a solution?


If you don't want your class type to be assignable then you can't use it in a container that requires that its value type is assignable. All of the C++ standard library containers have this requirement.

방법 3:

const does not mean "this value can only change under special circumstances." Rather, const means "Nothing you're allowed to do with it will cause it to change in any way (that you could observe)"

If you have a const qualified variable, you aren't allowed, by fiat of the compiler (and your own choice to qualify it with const in the first place), to do anything that would cause it to change. That's what const does. It might change in spite of you're actions, if it is a const reference to a non‑const object, or for any of a range of other reasons. If you as the programmer know that the referant is not actually constant, you can cast it away with const_cast and change that.

But in your case, a constant member variable, this isn't possible. The const qualified variable is cannot be a const reference to non‑const, because it's not a reference at all.

Edit: for a thrilling example of what this is all about and why you should behave yourself with regards to const correctness, lets have a look at what a real compiler actually does. Consider this short program:

int main() {
  const int i = 42; 
  const_cast<int&>(i) = 0; 
  return i;
}

And here's what LLVM‑G++ emits:

; ModuleID = '/tmp/webcompile/_2418_0.bc'
target datalayout = "e‑p:64:64:64‑i1:8:8‑i8:8:8‑i16:16:16‑i32:32:32‑i64:64:64‑f32:32:32‑f64:64:64‑v64:64:64‑v128:128:128‑a0:0:64‑s0:64:64‑f80:128:128‑n8:16:32:64"
target triple = "x86_64‑linux‑gnu"

define i32 @main() nounwind {
entry:
  %retval = alloca i32                            ; <i32*> [#uses=2]
  %0 = alloca i32                                 ; <i32*> [#uses=2]
  %i = alloca i32                                 ; <i32*> [#uses=2]
  %"alloca point" = bitcast i32 0 to i32          ; <i32> [#uses=0]
  store i32 42, i32* %i, align 4
  store i32 0, i32* %i, align 4
  store i32 42, i32* %0, align 4
  %1 = load i32* %0, align 4                      ; <i32> [#uses=1]
  store i32 %1, i32* %retval, align 4
  br label %return

return:                                           ; preds = %entry
  %retval2 = load i32* %retval                    ; <i32> [#uses=1]
  ret i32 %retval2
}

Of particular interest is the line store i32 0, i32* %i, align 4. This indicates that the const_cast was successful, we actually assigned a zero over the value that i had been initialized to.

But modifications to const qualifieds cannot result in an observable change. Thus GCC produces a fairly lengthy chain of putting 42 into %0, and then loating that 42 into %1, then storing it again into %retval, and then loading it into %retval2. Thus, G++ will have this code satisfy both requirements, the const was cast away but there was no observable change to i, main returns 42.


If you need a value that can be changed, for instance in the elements of a standard container, then you do not need const.

Consider using private: members with public getter and private setter methods.

방법 4:

I'll try to bundle the answers in short:

The main problem is that QList requires the assignment operator to be present because they internally use assignment. Thus they mix implementation with interface. So although YOU don't need the assignment operator QList won't work without it. source

<p>@ 3. There is std::List but it doesn't offer constant time access to elements, while QList does.</p>

<p>@ 2. It is possible by creating a new object with the copy constructor and the desired properties and returning it*. Although you circumvent the const property it is still better than using no const at all because you would allow the container to cheat here but still prevent users to do this themselves which was the original intention of making this member constant.</p>

But take into account that creating an overloaded assignment operator adds to the complexity of the code and might introduce more errors than the const‑ing of the members would solve in the first place.

<p>@ 1. In the end this seems to be the easiest solution. As long as it's private you just have to pay attention that the object doesn't change it itself.</p>

<p>@ 4. No way to force him. He wouldn't know how because the variable is constant and at some point he would have to do this‑>row = other.row with int const row; previously defined. And const means constant even in this case. one source</p>

<p>@ 5 QList has no options of this kind.</p>

Additional solutions:

  • Use pointer to objects instead of pure objects

*Not sure about this at the moment.

(by problemofficerfredoverflowJames McNellisSingleNegationEliminationproblemofficer)

참조 문서

  1. Constant class members, assignment operator and QList (CC BY‑SA 3.0/4.0)

#C++ #class-constants #assignment-operator #qlist #qt






관련 질문

파일의 암호화/복호화? (Encryption/ Decryption of a file?)

이상한 범위 확인 연산자가 있는 C++ typedef (C++ typedef with strange scope resolution operator)

개체 배열 매개변수--오류: '문자' 필드에 불완전한 유형이 있습니다. (Object array parameter--error: field ‘letters’ has incomplete type)

C++에서 메모리 삭제 (Deleting memory in c++)

C++ 프로그램을 실행할 수 없습니다. No se ejecuta el programa (C++ i can't run a program. No se ejecuta el programa)

컴파일 시 변수의 이름과 수명 (Name and lifetime of variables at compile time)

control-c 후 Visual Studio 콘솔 프로그램 충돌 (visual studio console program crashes after control-c)

멤버 변수에 std::enable_if 또는 유사한 메서드 사용 (Using std::enable_if or similar method on member variable)

ifstream input_file(filename); (I am receiving an error "no matching function to call" in the line ifstream input_file(filename);)

ESP8266에서 잠시 실행하면 JsonData 크기가 0이 됩니다. (JsonData size becomes zero after awhile of running in ESP8266)

합에 대한 속도 문제(제수의 합) (Speed problem for summation (sum of divisors))

벡터 벡터에서 하위 벡터의 첫 번째 값을 찾기 위해 begin() 및 end() 반복기의 범위를 지정하는 방법은 무엇입니까? (How to specify a range for begin() and end() iterators to find first value of sub vector in a vector of vectors?)







코멘트