从另一个列表的元素构造一个列表而不添加到堆内存
Construct one list from element of another list without adding to heap memory
我正在开发内存关键型应用程序。我首先生成一个列表,例如(C++11):
std::list<string> nodes({"Hello","Welcome", "Hi", "World"});
我现在需要用 'nodes.' 的第二个和第三个元素创建一个较小的列表,天真地,我会这样做:
std::list<string> sub_nodes;
sub_nodes.push_back(*std::next(nodes.begin(),1));
sub_nodes.push_back(*std::next(nodes.begin(),2));
但这显然是通过分配新内存在堆中为sub_nodes
分配内存。
*(sub_nodes.begin()) = "NotWelcome"; //changing first element
std::list<string>::iterator it;
for(it=nodes.begin();it!=nodes.end();++it) cout<<*it<<'\t';
cout<<'\n';
//Hello Welcome Hi World
for(it=sub_nodes.begin();it!=sub_nodes.end();++it)
cout<<*it<<'\t';
cout<<'\n';
//NotWelcome Hi
我希望完成的是让 sub_nodes
的元素与创建它们的 nodes
的元素占用相同的地址。换句话说,我希望对 sub_nodes
中的元素所做的更改反映在 nodes
中的那些元素中,反之亦然。在 C 链表中,这将是直截了当的,因为列表节点基本上是指针。我如何在 C++ 中完成相同的操作?
A std::list<T>
拥有它的元素。这是使用 std 容器的一个主要动机。他们管理元素的生命周期。如果您希望容器不拥有它的元素,那么不要让它存储 T
s。有几种选择。使用 std::list
的优点是 std::list
的迭代器不会轻易失效(例如 std::vector
可能会在每次插入时重新分配和复制所有元素,而 std::list
则不然).因此,您可以使用迭代器:
std::list< std::list<std::string>::iterator > sub_nodes;
sub_nodes.push_back( nodes.begin() );
// etc..
请注意,如果 nodes
使其迭代器无效,例如通过擦除元素,则 sub_nodes
可能包含无效条目。
您可以创建一个字符串指针列表。
std::list<std::string*> slist1;
slist1.push_back(new std::string("Hello"));
slist1.push_back(new std::string("Welcome"));
slist1.push_back(new std::string("Hi"));
slist1.push_back(new std::string("World"));
然后使用相同的指针创建另一个列表。
auto it = slist1.begin();
std::list<std::string*> slist2(std::next(it, 1), std::next(it, 3));
此 slist2
列表指针与 slist1
中的指针相同。现在更改任何指针都会在这两个地方得到反映。例如,下面的代码将 slist2 中的 "Welcome" 和 "Hi" 替换为 "abc"。更改也反映在 slist1 中,因为指针相同。
for (auto &s: slist2) {
std::cout << *s << "\n";
*s = "abc";
}
for (auto &s: slist1) {
std::cout << *s << " "; //prints Hello abc abc World
}
请注意,此代码不是异常安全的,必须手动删除该列表。为了异常安全和自动销毁,请使用智能指针。下面是一个使用 shared_ptr.
的例子
#include <iostream>
#include <memory>
#include <string>
#include <list>
int main()
{
std::list<std::shared_ptr<std::string>> slist1;
slist1.push_back(std::make_shared<std::string>("Hello"));
slist1.push_back(std::make_shared<std::string>("Welcome"));
slist1.push_back(std::make_shared<std::string>("Hi"));
slist1.push_back(std::make_shared<std::string>("World"));
auto it = slist1.begin();
std::list<std::shared_ptr<std::string>> slist2(std::next(it, 1), std::next(it, 3));
for (auto &s: slist2) {
std::cout << *s << " ";
*s = "abc";
}
for (auto &s: slist1)
std::cout << *s << " "; //prints Hello abc abc World
return 0;
}
您可以使用std::reference_wrapper
,它可以作为参考,并且可以存储在容器中。
std::list<std::reference_wrapper<std::string>> sub_nodes; // #include <functional>
请注意,尽管 std::reference_wrapper
具有到其值类型的隐式转换运算符 sometimes you still have to use its explicit get
method。例如,您必须使用
(*sub_nodes.begin()).get() = "NotWelcome";
更改引用的对象。
以下是完整的工作示例:
#include <iostream>
#include <functional>
#include <list>
#include <string>
int main()
{
std::list<std::string> nodes({"Hello","Welcome", "Hi", "World"});
std::list<std::reference_wrapper<std::string>> sub_nodes;
sub_nodes.push_back(*std::next(nodes.begin(), 1));
sub_nodes.push_back(*std::next(nodes.begin(), 2));
(*sub_nodes.begin()).get() = "NotWelcome";
for (auto it = nodes.begin(); it != nodes.end(); ++it) std::cout << *it << '\t';
std::cout << '\n';
// Hello NotWelcome Hi World
for (auto it = sub_nodes.begin(); it != sub_nodes.end(); ++it)
std::cout << (*it).get() << '\t';
std::cout << '\n';
// NotWelcome Hi
}
我正在开发内存关键型应用程序。我首先生成一个列表,例如(C++11):
std::list<string> nodes({"Hello","Welcome", "Hi", "World"});
我现在需要用 'nodes.' 的第二个和第三个元素创建一个较小的列表,天真地,我会这样做:
std::list<string> sub_nodes;
sub_nodes.push_back(*std::next(nodes.begin(),1));
sub_nodes.push_back(*std::next(nodes.begin(),2));
但这显然是通过分配新内存在堆中为sub_nodes
分配内存。
*(sub_nodes.begin()) = "NotWelcome"; //changing first element
std::list<string>::iterator it;
for(it=nodes.begin();it!=nodes.end();++it) cout<<*it<<'\t';
cout<<'\n';
//Hello Welcome Hi World
for(it=sub_nodes.begin();it!=sub_nodes.end();++it)
cout<<*it<<'\t';
cout<<'\n';
//NotWelcome Hi
我希望完成的是让 sub_nodes
的元素与创建它们的 nodes
的元素占用相同的地址。换句话说,我希望对 sub_nodes
中的元素所做的更改反映在 nodes
中的那些元素中,反之亦然。在 C 链表中,这将是直截了当的,因为列表节点基本上是指针。我如何在 C++ 中完成相同的操作?
A std::list<T>
拥有它的元素。这是使用 std 容器的一个主要动机。他们管理元素的生命周期。如果您希望容器不拥有它的元素,那么不要让它存储 T
s。有几种选择。使用 std::list
的优点是 std::list
的迭代器不会轻易失效(例如 std::vector
可能会在每次插入时重新分配和复制所有元素,而 std::list
则不然).因此,您可以使用迭代器:
std::list< std::list<std::string>::iterator > sub_nodes;
sub_nodes.push_back( nodes.begin() );
// etc..
请注意,如果 nodes
使其迭代器无效,例如通过擦除元素,则 sub_nodes
可能包含无效条目。
您可以创建一个字符串指针列表。
std::list<std::string*> slist1;
slist1.push_back(new std::string("Hello"));
slist1.push_back(new std::string("Welcome"));
slist1.push_back(new std::string("Hi"));
slist1.push_back(new std::string("World"));
然后使用相同的指针创建另一个列表。
auto it = slist1.begin();
std::list<std::string*> slist2(std::next(it, 1), std::next(it, 3));
此 slist2
列表指针与 slist1
中的指针相同。现在更改任何指针都会在这两个地方得到反映。例如,下面的代码将 slist2 中的 "Welcome" 和 "Hi" 替换为 "abc"。更改也反映在 slist1 中,因为指针相同。
for (auto &s: slist2) {
std::cout << *s << "\n";
*s = "abc";
}
for (auto &s: slist1) {
std::cout << *s << " "; //prints Hello abc abc World
}
请注意,此代码不是异常安全的,必须手动删除该列表。为了异常安全和自动销毁,请使用智能指针。下面是一个使用 shared_ptr.
的例子#include <iostream>
#include <memory>
#include <string>
#include <list>
int main()
{
std::list<std::shared_ptr<std::string>> slist1;
slist1.push_back(std::make_shared<std::string>("Hello"));
slist1.push_back(std::make_shared<std::string>("Welcome"));
slist1.push_back(std::make_shared<std::string>("Hi"));
slist1.push_back(std::make_shared<std::string>("World"));
auto it = slist1.begin();
std::list<std::shared_ptr<std::string>> slist2(std::next(it, 1), std::next(it, 3));
for (auto &s: slist2) {
std::cout << *s << " ";
*s = "abc";
}
for (auto &s: slist1)
std::cout << *s << " "; //prints Hello abc abc World
return 0;
}
您可以使用std::reference_wrapper
,它可以作为参考,并且可以存储在容器中。
std::list<std::reference_wrapper<std::string>> sub_nodes; // #include <functional>
请注意,尽管 std::reference_wrapper
具有到其值类型的隐式转换运算符 sometimes you still have to use its explicit get
method。例如,您必须使用
(*sub_nodes.begin()).get() = "NotWelcome";
更改引用的对象。
以下是完整的工作示例:
#include <iostream>
#include <functional>
#include <list>
#include <string>
int main()
{
std::list<std::string> nodes({"Hello","Welcome", "Hi", "World"});
std::list<std::reference_wrapper<std::string>> sub_nodes;
sub_nodes.push_back(*std::next(nodes.begin(), 1));
sub_nodes.push_back(*std::next(nodes.begin(), 2));
(*sub_nodes.begin()).get() = "NotWelcome";
for (auto it = nodes.begin(); it != nodes.end(); ++it) std::cout << *it << '\t';
std::cout << '\n';
// Hello NotWelcome Hi World
for (auto it = sub_nodes.begin(); it != sub_nodes.end(); ++it)
std::cout << (*it).get() << '\t';
std::cout << '\n';
// NotWelcome Hi
}