C++ 在C+;中,什么是变量函数的良好类型安全替代方案+;?
与此相结合。对于以下看似基本的问题,我很难想出一个好的类型安全解决方案。我有一个班级音乐播放列表,其中有一个应该播放的歌曲列表。看起来很简单,对吧,只需制作一个包含队列中所有歌曲的std::列表,并让用户可以使用它。然而,出于必要,音频解码和音频渲染在不同的线程上进行。因此,列表需要受到互斥保护。通常情况下,使用我的库的其他程序员会忘记互斥。这显然导致了“奇怪”的问题 所以一开始我只是为这个班写了setterC++ 在C+;中,什么是变量函数的良好类型安全替代方案+;?,c++,type-safety,variadic,C++,Type Safety,Variadic,与此相结合。对于以下看似基本的问题,我很难想出一个好的类型安全解决方案。我有一个班级音乐播放列表,其中有一个应该播放的歌曲列表。看起来很简单,对吧,只需制作一个包含队列中所有歌曲的std::列表,并让用户可以使用它。然而,出于必要,音频解码和音频渲染在不同的线程上进行。因此,列表需要受到互斥保护。通常情况下,使用我的库的其他程序员会忘记互斥。这显然导致了“奇怪”的问题 所以一开始我只是为这个班写了setter struct music{}; class music_playlist{ priva
struct music{};
class music_playlist{
private:
std::list<music> playlist;
public:
void add_song(music &song){playlist.push_back(song);}
void clear(){playlist.clear();}
void set_list(std::list<music> &songs){playlist.assign(songs.begin(),songs.end());}
//etc
};
现在更容易看到一首歌是被添加了两次还是没有被收录。然而,在解决方案A中,如果NULL不在列表的末尾,并且不是跨平台的,那么它将崩溃。在solutionB中,您必须计算可能导致几个错误的参数数量。此外,没有一个解决方案是类型安全的,用户可以传入一个不相关的类型,并在运行时等待崩溃。这似乎不是一个可持续的解决方案。然后我遇到了std::initializer\u list。无法使用它我开发的一些编译器还不支持它。所以我试着模仿它。我最终得到了下面这个解决方案
这将导致用户代码看起来像这样
struct music_playlist{
list<music> queue;
//...
};
int main (int argc, const char * argv[])
{
music_playlist playlist;
music song1;
music song2;
music song3;
music song4;
playlist.queue = song1,song2; // The queue now contains song1 and song2
playlist.queue+= song1,song3,song4; //The queue now contains two song1s and song2-4
playlist.queue = song2; //the queue now only contains song2
return 0;
}
这使我对那种解决办法感到厌烦。那么你有没有更好的解决方案
另外,上面的代码都没有被编译过,它们只是出于示例目的。首先想到的问题是这是否是一个问题,以及这是否是一个值得解决的问题。因为您正在创建一个接口,所以您的客户机将是用户代码(而不是人员代码)。您的客户会在代码中硬编码播放列表多少次,而不是从文件中存储、加载或根据用户选择构建播放列表 思考该功能的实际价值,并将其与用户如何使用您的库的影响进行比较,思考用户在更改界面时可能遇到的问题 最简单的解决方案是接受迭代器来构造/重置列表,然后让用户处理这个问题。当然,他们可以按照您展示的方式构建自己的容器,但他们也可以使用Boost.Assignment来处理锅炉板,因此他们的用户代码如下所示:
std::vector<music> songs = boost::assign::list_of()( song1 )( song2 );
play_list.set( songs.begin(), songs.end() );
老实说,我不明白单行添加
song1、song2、song3、song4、song5、song6
比多行查找错误更好吗?为什么人们会读一本而不读另一本?在我看来,如果您的变量不在列表/数组中,那么您在调用代码中犯了错误,这不是您要解决的问题……您示例中的所有错误都与并发无关,只是编程不好。@LittledV,不幸的是,这是我必须处理的问题。作为该库的目标市场,它具有如此广泛的编程能力。他们中的一些是10年以上的经验领域的专家,而其他人则参与编写他们的第一个C++程序。库的整个设计试图通过简单地浏览源文件,使尽可能多的bug导致编译时错误或易于检测。这是唯一一个我无法应用这种方法的领域。@RTS-只是让我的回答更加有力:假设客户是dumba**-确保你的代码是防污染的。如果需要保护,请自己保护它。至于两次添加同一首歌而错过另一首歌,你真的无能为力。在我看来,两次播放同一首歌是一个可行的用例,所以你不应该因为错误而忽略它。我太累了,无法写出一个实质性的答案,所以我将把这个留在这里。。不要使用逗号运算符,你应该真正坚持标准的迭代器是最好的解决方案。+1对于Boost.Assign,Boost的另一个很少有人知道的部分。
playlist1.set_listA(&song1,&song2,&song3,&song4,&song5,&song6,NULL);
//playlist1.set_listA(&song1,&song2,&song3,&song4,&song5,&song6); runtime error!!
//or
playlist2.set_listB(6,song1,song2,song3,song4,song5,song6);
struct music_playlist{
list<music> queue;
//...
};
int main (int argc, const char * argv[])
{
music_playlist playlist;
music song1;
music song2;
music song3;
music song4;
playlist.queue = song1,song2; // The queue now contains song1 and song2
playlist.queue+= song1,song3,song4; //The queue now contains two song1s and song2-4
playlist.queue = song2; //the queue now only contains song2
return 0;
}
//lets combine differnt playlists
new_playlist.queue = song1 //the first playlist
,(song3,song4) //the second playlist //opps, I didn't add song 3!
, song5;
std::vector<music> songs = boost::assign::list_of()( song1 )( song2 );
play_list.set( songs.begin(), songs.end() );
music songs[2] = { song1, song2 };
play_list:set( songs, songs + 2 ); // add your preferred magic to calculate the size