У меня есть код ниже:
#include <iostream>
#include <list>
using namespace std;
class YTchannel{
public:
string name;
string owner;
int subs;
list<string> video_title;
};
int main(){
YTchannel ytc;
ytc.video_title = {"A", "B", "C"};
for(string videotitle: ytc.video_title){
for(int i=1;i<=videotitle.size();i++){
cout<<i<<videotitle<<endl;
break;
}
}
Я хочу отобразить список заголовков видео с их соответствующим номером: 1А 2Б 3С
Но если я запущу код, я получу: 1А 1Б 1С
Что ж, довольно очевидно: внутренний цикл перебирает длину заголовков... Попробуйте вставить заголовок длиннее одного символа, например "ABC", и вы заметите: 1ABC 2ABC 3ABC (наряду с, возможно, другим выводом, если вы оставите их в списке .
Почему это помечено как упс? Я действительно не вижу никакой связи с ООП.
Обратите внимание, что если у вас нет особых требований к использованию списка, контейнером по умолчанию в C++ почти всегда должен быть std::vector.
То, что вы должны прочитать о использовании пространства имен std — до того, как эта плохая практика превратится в плохую привычку ;)
Кроме того, наличие безусловного break внутри цикла for гарантирует, что он работает только один раунд. Как если бы не было петли...
Использование ключевого слова auto делает ваш код более удобным для сопровождения, учтите, что вам нужно заменить std::string на какой-то другой тип; тогда вам не нужно будет настраивать петлю: for(auto videotitle : tyc.video_title)





Вы печатаете длину строки ("A", "B" или "C"), а не списка. Вы хотите:
ytc.video_title = {"A", "B", "C"};
auto it = ytc.begin()
for(size_t i =0; i < ytc.size(); ++i){
cout<<i<<*it++<<endl;
}
Однако то, что вы, вероятно, действительно хотите, это:
#include <iostream>
#include <vector>
#include <algorithm>
// Include the headers for std::string
#include <string>
// Don't use 'using namespace std'
// Structs are all public by default, so they're a better choice than a class here
struct YTchannel{
std::string name;
std::string owner;
int subs;
// Vector is a better choice than list unless you know why it isn't
std::vector<string> video_title;
};
int main(){
YTchannel ytc;
ytc.video_title = {"A", "B", "C"};
for(auto it = ytc.begin(); it != ytc.end(); ++it){
std::cout << std::distance(ytc.begin(), it) << videotitle << std::endl;
}
Лично я бы предпочел: for(auto it = begin(); it != end(); ++it) { std::cout << it - begin() << ...; } избегать дополнительной переменной, видимой вне цикла. Хотя очевидно, что цикл итератора используется реже, он в любом случае более идиоматичен (или почему цикл for, основанный на диапазоне, определяется int в терминах иначе?). Конечно, требуется переключиться на std::vector, но в любом случае это рекомендуется.
@Aconcagua Я согласен - и я не уверен, что согласен, что он все равно используется меньше. Но в этом случае самая тривиальная реализация, вероятно, та, которая перебирает индексы, а не итераторы. Мое предпочтительное решение, конечно, просто использовать итераторы, std::vector и std::distance вместо того, чтобы вообще иметь счетчик :)
Что ж, цикл for на основе счетчика и диапазона (особенно в варианте С++ 20, см. другие ответы) по-прежнему является привлекательной альтернативой — и если есть причины сохранить список (например, для требования указателей на, которые могут стать недействительными с std::vector) тогда я бы определенно пошел по этому пути ;) — с сохранением списка std::distance потребовалась бы внутренняя итерация — невидимое превращение печати в алгоритм O(n²) :(
Да, кстати: for(auto& s : vector) { auto distance = &s - &vector.front(); } было бы еще альтернативой разрешить диапазон, основанный на цикле for без дополнительной переменной, хотя содержащаяся арифметика указателя может перегрузить автора вопроса;)
@Aconcagua, если список требуется, я согласен. Но то, что мы, вероятно, имеем здесь, это Java-программист, который выбрал неправильный контейнер :) (также, если вам нужны гарантии валидности итератора, используйте двухстороннюю очередь)
std::deque имеет более слабые гарантии, если стереть посередине! См. en.cppreference.com/w/cpp/container/deque#Iterator_invalidationПервая петля:
for(string videotitle: ytc.video_title)
перебирает все строки в списке.
Второй цикл:
for(int i=1;i<=videotitle.size();i++)
перебирает все символы в текущей строке. И в этом цикле вы печатаете всю строку на каждой итерации.
Простое решение состоит в том, чтобы сохранить отдельный счетчик, который вы увеличиваете в одном первом цикле:
unsigned counter = 1;
for (auto const& title : yts.video_titles)
{
std::cout << counter++ << ' ' << title << '\n';
}
Мне нравится вариант С++ 20 из другого ответа - хотя и не (пока?) Правильный - за то, что не требуется переменная, видимая вне тела цикла; рекомендовал бы size_t как правильный тип (соответствующий size() возвращаемому значению контейнеров) — несмотря на то, что unsigned несоответствие должно быть нереалистичным;)
У вас есть «перерыв» в вашем цикле, поэтому вы никогда не увеличиваете счетчик.
Кроме того, в C++20 вы можете сузить область действия, используя оператор init в цикле на основе диапазона.
#include <iostream>
#include <list>
using namespace std;
class YTchannel{
public:
string name;
string owner;
int subs;
list<string> video_title;
};
int main(){
YTchannel ytc;
ytc.video_title = {"A", "B", "C"};
int counter = 0;
for(string videotitle : ytc.video_title){
cout<<++counter<<videotitle<<endl;
}
// C++20
//YTchannel ytc;
//ytc.video_title = {"A", "B", "C"};
//for(int counter = 0; string videotitle : ytc.video_title){
// cout<<++counter<<videotitle<<endl;
//}
}
Да, я обновил ответ до того, как вы сделали свой комментарий. Что касается ссылок и прочего - это просто вопрос использования. Может быть, кто-то захочет сделать копию вместо того, чтобы брать ссылку. ОП, очевидно, новичок, и вы, вероятно, сбиваете его с толку, вводя ссылки, которые он, вероятно, не знает. НЕ усложняйте.
@ bielu000 bielu000 не уверен, что я согласен с тем, что настаивать на хорошем стиле кодирования с самого начала слишком сложно.
Хороший стиль кодирования — это не то, что должно интересовать новичка. Точка. Я работал со студентами, и они обычно боятся C++ именно тем, что навязывают им слишком много вещей одновременно, они не понимают. Придет время, когда новичок узнает, что такое ссылка, как ее использовать и как она влияет на производительность.
Имею некоторые трудности с тем, чтобы договориться, поскольку мой опыт показывает, что трудно отказаться от вредных привычек, когда они уже приобретены, через что не нужно проходить, если вы изучаете веревки в самом начале. Если ссылки действительно все еще неизвестны – учитывая их важность – то я бы сказал, что они будут введены в этом курсе определенно слишком поздно. Признал, неисправность потенциально проблематична для исправления здесь :(
Зачем вы написали вложенный цикл? И почему вы используете
list<string>вместоvector<string>?