如何从参数包获取指向对象的指针

How to get the pointer to an object from a parameter pack

本文关键字:对象 指针 取指 包获 参数      更新时间:2023-10-16

我无法使用参数包让 2 个相同类型的不同对象指向不同对象的指针。这是 Controller.h:

using expand_type = int[];
template<typename... Ts> class Controller {
public:
Controller(int i, string s, Ts... args): id(i), name(s) {
expand_type{ (add_component(&args), 0)... };
}
void add_component(Test2* a) {
device_.push_back(a);
}
void print() {
cout<<name<<":"<<endl;
cout<<"================="<<endl;
for (vector<Test2*>::size_type i = 0; i < device_.size(); ++i) {
cout<<device_[i]->print()<<endl;
}
cout<<"================="<<endl;
}
private:
vector<Test2*> device_;
int id;
string name;
};

这是我的测试2.h:

class Test2 {
public:
Test2(): x(0) {}
Test2(int a): x(a) {}
int print() const {
return x;
}
private:
int x;
};

我的问题是,当我制作两个单独的控制器对象时,它们在各自的向量中共享它们的 Test2 对象。这是我的主要:

int main() {
Test2 b(69);
Test2 c(666);
Test2 d(943754);
Controller<Test2, Test2, Test2, Test2> x(2, string("Peter"), 70, b, c, d);
Controller<> y(2, string("Pietje"));
Controller<Test2, Test2, Test2, Test2> z(3, string("Jan"), 909, 808, 1, 2);
x.print();
y.print();
z.print();
cout<<"hello"<<endl;
return 0;
}

则输出为:

Peter:
=================
0
808
1
2
=================
Pietje:
=================
=================
Jan:
=================
0
808
1
2
=================
hello

我希望控制器的不同对象具有指向不同 Test2 对象的不同指针,而我 v3 不知道如何。

另外,作为一个附带问题;我的第一个指针总是变成 0,除非它是向量中唯一的对象。

任何帮助不胜感激!

避开时髦的行为,你在这里的主要问题是所有权:Controller是否拥有这些设备,如果不是,谁拥有?假设控制器不拥有设备。那么这样的事情会引起问题

Controller<...> z(3, string("Jan"), 909, 808, 1, 2);
^^^ temporary object's lifetime ends immediately
it won't have a valid address to point to

一旦你计划好了,你的体验会好得多。假设Controller拥有这些设备:只需使用Test2向量即可设置。

下一个问题是可变参数模板。看起来device_都是相同的类型,可变参数模板的唯一用途是具有可变数量的构造函数参数。如果是这样,只需为构造函数使用可变参数模板,并使类成为简单的类型:

class Controller {
public:
template<typename... Ts>
Controller(int i, string s, Ts&&... args): id(i), name(s), device_ { std::forward<Ts>(args)... } { }
// ...
};

将它们放在一起,一切都按预期工作:

#include <vector>
#include <string>
#include <iostream>
using namespace std;
class Test2 {
public:
Test2(): x(0) {}
Test2(int a): x(a) {}
int print() const {
return x;
}
private:
int x;
};
class Controller {
public:
template<typename... Ts>
Controller(int i, string s, Ts&&... args): id(i), name(s), device_ { std::forward<Ts>(args)... } { }
void print() {
cout<<name<<":"<<endl;
cout<<"================="<<endl;
for (auto& device : device_) {
cout<<device.print()<<endl;
}
cout<<"================="<<endl;
}
private:
vector<Test2> device_;
int id;
string name;
};
int main() {
Test2 b(69);
Test2 c(666);
Test2 d(943754);
Controller x(2, string("Peter"), 70, b, c, d);
Controller y(2, string("Pietje"));
Controller z(3, string("Jan"), 909, 808, 1, 2);
x.print();
y.print();
z.print();
cout<<"hello"<<endl;
return 0;
}
Peter:
=================
70
69
666
943754
=================
Pietje:
=================
=================
Jan:
=================
909
808
1
2
=================
hello

演示:https://godbolt.org/z/bLjgaf


更新: 根据您的请求,假设Controller仅存储原始指针,并不拥有Test2设备。首先,您必须将引用传递给构造器,以便可以访问对象的地址:

class Controller {
public:
template<typename... Ts>
Controller(int i, string s, Ts&... args): id(i), name(s), device_ { &args... } { }
// ...
};

然后,您必须确保传递它的每个对象都比控制器活得更久

Test2 b(69);
Test2 c(666);
Test2 d(943754);
Controller x(2, string("Peter"), b, c, d); // this is fine
Controller y(2, string("Pietje"));         // this is fine
Controller z(3, string("Jan"), 909, 808, 1, 2); // uh oh!

到目前为止,我们只讨论过堆栈分配的Test2对象。您还可以动态分配对象并获取指向该对象的指针。此指针只有一个所有者,您可以使用std::move转让所有权:

std::unique_ptr<Test2> = std::make_unique<Test2>(42);

您还可以创建具有共享所有权的指针。您可以复制此指针,最后一个幸存的指针将清理对象:

std::shared_ptr<Test2> = std::make_shared<Test2>(42);

但是,如果你想了解记忆模型,我不能推荐这个。很多时候,人们用它来避免思考记忆模型。如果一切都有明确的所有者,它会让你的生活更轻松。