STL 또는 Qt 컨테이너? Qt는 용기 (사용 장단점 무엇인가

Qt는 용기 (사용 장단점 무엇인가 QMap, QVector그들의 STL 당량 이상 등)?

Qt를 선호하는 이유는 다음과 같습니다.

  • Qt 컨테이너는 Qt의 다른 부분으로 전달 될 수 있습니다. 예를 들어,는를 채우는 데 사용될 수있는 QVariantQSettings(일부 제한 한 것처럼, 전용 QListQMap/ QHash그 키가 스트링 허용된다).

다른 것이 있습니까?

편집 : 응용 프로그램이 이미 Qt에 의존한다고 가정합니다.



답변

나는 std::(w)stringSTL 컨테이너를 독점적 으로 사용 하고 Qt와 동등한 것으로 변환하거나 그로부터 변환하는 것으로 시작 했지만 이미 전환했으며 QStringQt의 컨테이너를 점점 더 많이 사용하고 있음을 알았습니다.

문자열 QString과 관련하여 훨씬 더 완벽한 기능을 제공 std::basic_string하며 완전히 유니 코드를 인식합니다. 또한 효율적인 COW 구현을 제공하므로 크게 의존합니다.

Qt의 컨테이너 :

  • 에서와 동일한 COW 구현을 제공합니다 QString. 이는 Qt의 foreach매크로 (사본 수행)를 사용하거나 메타 유형 또는 신호 및 슬롯 을 사용할 때 매우 유용 합니다.
  • STL 스타일 이터레이터 또는 Java 스타일 이터레이터를 사용할 수 있습니다
  • 스트리밍 가능 QDataStream
  • Qt의 API에서 광범위하게 사용됩니다
  • 운영 체제 전체에서 안정적으로 구현됩니다. STL 구현은 C ++ 표준을 준수해야하지만 원하는대로 자유롭게 수행 할 수 있습니다 ( std::stringCOW 논쟁 참조 ). 일부 STL 구현은 특히 나쁩니다.
  • TR1을 사용하지 않으면 사용할 수없는 해시 제공

QTL은 J. Blanchette에 의해 요약 된 STL과는 다른 철학을 가지고 있습니다 . “STL의 컨테이너가 원시 속도에 최적화 된 반면, Qt의 컨테이너 클래스는 편의성, 최소 메모리 사용 및 최소 코드 확장을 제공하도록 신중하게 설계되었습니다.”
위의 링크는 QTL 구현 및 사용되는 최적화에 대한 자세한 정보를 제공합니다.


답변

질문에 대답하기가 어렵습니다. 그것은 철학적 / 주관적 논쟁으로 귀결 될 수 있습니다.

그 말은 …

나는 “로마에있을 때 … 로마인들이하는 것처럼”

Qt 땅에 있다면 Qt’ians처럼 코딩하십시오. 이것은 가독성 / 일관성 문제만을위한 것이 아닙니다. stl 컨테이너에 모든 것을 저장하면 어떤 일이 발생하는지 고려한 다음 모든 데이터를 Qt 함수에 전달해야합니다. 실제로 Qt 컨테이너에 물건을 복사하는 코드 묶음을 관리하고 싶습니까? 코드는 이미 Qt에 크게 의존하므로 stl 컨테이너를 사용하여 더 “표준”으로 만드는 것과는 다릅니다. 컨테이너를 유용하게 사용할 때마다 컨테이너의 요점은 무엇입니까? 해당 Qt 컨테이너에 복사해야합니까?


답변

Qt 컨테이너는 STL 컨테이너보다 제한됩니다. STL이 우수한 곳의 몇 가지 예 (이 모든 것이 과거에 부딪 쳤습니다) :

  • STL은 모든 Qt는 버전 변경되지 않습니다, 표준화 (Qt는 2 없었다 QList포인터 기반) 및 ( QValueList; Qt는 3 있었다 (가치 기반은) QPtrListQValueListQt는 4 지금 갖고 QList와 같은 모든에서 그것의 아무것도 QPtrList 또는 QValueList ).
    (. 즉, 당신은 Qt는 컨테이너를 사용하게하더라도, STL 호환 API의 하위 집합을 사용 push_back()하지 append(), front()하지 first(), …) 모두 Qt2-> 3 Qt3-에서 Qt는 5 와서 다시 한번 이식 피하기 위해> 4 Qt 컨테이너의 변경은 코드 변경이 가장 필요한 변경 중 하나였습니다.
  • STL 양방향 컨테이너에는 모두 rbegin()/ rend()가 있으며 역 반복 대칭을 정방향 반복으로 만듭니다. 모든 Qt 컨테이너에 컨테이너가 포함되어 있지는 않기 때문에 (반복되는 컨테이너에는 해당되지 않음) 역 반복은 불필요하게 복잡합니다.
  • STL 컨테이너는 insert()다르지만 호환 가능한 반복자 유형의 범위 를 가지므로 std::copy()훨씬 덜 자주 필요합니다.
  • STL 컨테이너에는 Allocator템플릿 인수가있어 Qt (fork of required )와 비교하여 커스텀 메모리 관리가 간단합니다 (typedef 필요 ). EDIT 20171220 : C ++ 11 및 C ++ 17에 따라 할당 자 디자인의 진보로 인해 Qt가 줄어 듭니다 . 예 : John Lakos의 강연 ( 2 부 ).QLineEdits/QString/secqstring/
  • 에 해당하는 Qt는 없습니다 std::deque.
  • std::list있다 splice(). 내가 자신을 사용하는 것을 찾을 때마다 std::list필요하기 때문 splice()입니다.
  • std::stack, std::queue로 제대로, 자신의 기본 컨테이너를 집계하고 상속하지 않습니다 QStack, QQueue않습니다.
  • QSet같은 std::unordered_set것이 아닙니다 std::set.
  • QListA는 단지 이상한 .

위의 많은 것들이 Qt에서 매우 쉽게 해결할 수 있지만 Qt 의 컨테이너 라이브러리는 현재 개발 포커스가 부족한 것으로 보입니다.

EDIT 20150106 : Qt 5 컨테이너 클래스에 C ++ 11 지원을 가져 오는 데 약간의 시간을 보낸 후 작업 가치가 없다고 결정했습니다. C ++ 표준 라이브러리 구현에 적용되는 작업을 살펴보면 Qt 클래스가 결코 따라 잡지 않을 것이 분명합니다. 우리는 현재 Qt 5.4를 출시QVector 했지만 여전히 재 할당의 요소를 옮기지emplace_back()않거나 rvalue가없거나 rvalue-입니다push_back()… … 또한 최근에QOptional클래스 템플릿을거부하고std::optional대신기다렸습니다. 마찬가지로std::unique_ptr. 트렌드가 계속되기를 바랍니다.


답변

이러한 주장을 실제 측정 가능한 현상으로 나누겠습니다.

  • 더 가벼움 : Qt 컨테이너는 STL 컨테이너보다 적은 메모리를 사용합니다
  • 더 안전한 : Qt 컨테이너는 부적절하게 사용될 기회가 적습니다.
  • 더 쉬워 진 : Qt 컨테이너는 지적 부담이 적습니다.

더 쉬움

이 문맥에서 주장하는 것은 자바 스타일 반복이 STL 스타일보다 어떻게 든 “더 쉽다”는 것입니다. 따라서이 추가 인터페이스로 인해 Qt가 더 사용하기 쉽습니다.

자바 스타일 :

QListIterator<QString> i(list);
while (i.hasNext())
    qDebug() << i.next();

STL 스타일 :

QList<QString>::iterator i;
for (i = list.begin(); i != list.end(); ++i)
    qDebug << *i;

Java 반복자 스타일은 조금 작고 깨끗하다는 이점이 있습니다. 문제는 더 이상 STL 스타일이 아닙니다.

C ++ 11 STL 스타일

for( auto i = list.begin(); i != list.end(); ++i)
    qDebug << *i;

또는

C ++ 11 foreach 스타일

for (QString i : list)
    qDebug << i;

C ++ 11을 지원하지 않는 한 다른 것을 사용할 이유가 전혀없는 매우 간단합니다.

그러나 내가 가장 좋아하는 것은 다음과 같습니다.

BOOST_FOREACH(QString i, list)
{
    qDebug << i;
}

보시다시피,이 인터페이스는 이미 매끄럽고 간결하며 현대적인 인터페이스 외에 추가 인터페이스를 제외하고는 아무것도 얻지 못합니다. 이미 안정적이고 사용 가능한 인터페이스 위에 불필요한 추상화 수준을 추가 하시겠습니까? “보다 쉬운”아이디어는 아닙니다.

또한 Qt foreach 및 Java 인터페이스는 오버 헤드를 추가합니다. 그것들은 구조를 복사하고 불필요한 간접적 인 수준을 제공합니다. 이처럼 보이지 않을 수도 있지만 왜 그렇게 간단하지 않은 인터페이스를 제공하기 위해 오버 헤드 계층을 추가합니까? java에는 연산자 오버로딩이 없기 때문에 Java에는이 인터페이스가 있습니다. C ++는 않습니다.

더 안전한

Qt가 제공하는 정당성은 암시 적 공유 문제이며 암시 적이거나 문제가 아닙니다. 그러나 공유는 포함됩니다.

QVector<int> a, b;
a.resize(100000); // make a big vector filled with 0.

QVector<int>::iterator i = a.begin();
// WRONG way of using the iterator i:
b = a;
/*
Now we should be careful with iterator i since it will point to shared data
If we do *i = 4 then we would change the shared instance (both vectors)
The behavior differs from STL containers. Avoid doing such things in Qt.
*/

첫째, 이것은 암시 적이 지 않습니다. 한 벡터를 다른 벡터에 명시 적으로 할당하고 있습니다. STL 반복자 사양은 반복자가 컨테이너에 속한다는 것을 명확하게 나타내므로 b와 a 사이에 공유 컨테이너를 명확하게 소개했습니다. 둘째, 이것은 문제가되지 않습니다. 반복자 스펙의 모든 규칙을 따르는 한 절대로 아무 문제가 없습니다. 문제가있는 유일한 시간은 다음과 같습니다.

b.clear(); // Now the iterator i is completely invalid.

Qt는이 시나리오에서 문제가 발생하는 것과 같은 것을 의미하는 것처럼 이것을 지정합니다. 그렇지 않습니다. 이터레이터는 무효화되고 여러 분리 된 영역에서 액세스 할 수있는 것과 마찬가지로 이것이 작동하는 방식입니다. 실제로 이것은 Qt의 Java 스타일 반복자와 함께 쉽게 발생합니다. 암시 적 공유에 크게 의존하기 때문입니다. 이는 여기 및 기타 여러 영역 에서 설명한 반 패턴 입니다. 이 “최적화”가 멀티 스레딩으로 점점 더 이동하는 프레임 워크에서 사용되는 것은 특히 이상해 보이지만, 그것은 당신을위한 마케팅입니다.

거룻배

이것은 조금 까다 롭습니다. 쓰기시 복사 및 암시 적 공유 및 성장 전략을 사용하면 컨테이너가 특정 시간에 사용할 메모리 양을 실제로 보장하기가 매우 어렵습니다. 이것은 강력한 알고리즘 보장을 제공하는 STL과 다릅니다.

우리 는 벡터의 최소 낭비 공간이 벡터 길이의 제곱근이라는 것을 알고 있지만 Qt에서는 이것을 구현할 방법이없는 것 같습니다. 그들이 지원하는 다양한 “최적화”는이 중요한 공간 절약 기능을 배제 할 것입니다. STL은이 기능을 필요로하지 않으며 (이는 대부분 두 배의 성장을 사용하므로 더 낭비입니다) 필요한 경우 최소한이 기능을 구현할 수 있다는 점에 유의해야합니다.

XOr 연결을 사용하여 사용 된 공간을 크게 줄일 수있는 이중 연결 목록도 마찬가지입니다. 다시 말하지만, 이것은 성장과 COW에 대한 요구로 인해 Qt에서는 불가능합니다.

COW는 실제로 더 가벼운 것을 만들 수 있지만 boost 에서 지원하는 것과 같은 Intrusive Containers도 가능 하며 Qt는 이전 버전에서 자주 사용했지만 더 이상 사용하기 어렵고 안전하지 않으며 부담을 가하기 때문에 더 이상 사용되지 않습니다. 프로그래머에. COW는 훨씬 덜 관입적인 솔루션이지만 위에 제시된 이유로 매력이 없습니다.

메모리 비용이 같거나 Qt의 컨테이너보다 적은 STL 컨테이너를 사용할 수없는 이유는 없으며, 주어진 시간에 얼마나 많은 메모리를 낭비하는지 실제로 알 수 있다는 이점이 있습니다. 불행히도, 원시 메모리 사용량에서 두 ​​가지를 비교하는 것은 불가능합니다. 그러한 벤치 마크는 사용 사례마다 크게 다른 결과를 보여 주므로 STL이 수정하도록 설계된 정확한 종류의 문제입니다.

결론적으로

복사 비용을 부과하지 않고 가능한 경우 Qt 컨테이너를 사용하지 말고 가능하면 랩퍼 또는 새 구문을 통해 STL 유형 반복을 사용하십시오.


답변

STL 컨테이너 :

  • 성능 보장
  • 성능을 보장하는 STL 알고리즘에 사용할 수 있습니다
  • Boost와 같은 타사 C ++ 라이브러리에서 활용할 수 있습니다.
  • 표준이며 독점 솔루션보다 오래 지속될 가능성이 있음
  • 알고리즘 및 데이터 구조의 일반적인 프로그래밍을 장려하십시오. STL을 준수하는 새로운 알고리즘 및 데이터 구조를 작성하면 STL이 이미 제공 한 것을 무료로 이용할 수 있습니다.

답변

Qt 컨테이너는 COW (Copy On Write) 관용구를 사용합니다.


답변

주요 문제 중 하나는 Qt의 API가 Qt의 컨테이너에 데이터를 제공 할 것을 기대한다는 것입니다. 따라서 Qt 컨테이너를 앞뒤로 변환하지 않고 간단히 Qt 컨테이너를 사용할 수도 있습니다.

또한 이미 Qt 컨테이너를 사용하고 있다면 STL 헤더 파일을 포함하지 않고 STL 라이브러리에 링크 할 필요가 없으므로 독점적으로 사용하는 것이 약간 더 좋습니다. 그러나 툴체인에 따라 어쨌든 발생할 수 있습니다. 순전히 디자인 관점에서 일관성은 일반적으로 좋은 것입니다.