【问题标题】:STL vector used in managed code托管代码中使用的 STL 向量
【发布时间】:2013-04-19 18:06:30
【问题描述】:

操作系统:xp
IDE:VS 2008
在我用 Visual C++ 做的项目中,我已经在托管类中声明了一个 std::vector

std::vector<pts> dataPoints;//this gives error c4368 : mixed type not allowed 

但是这行得通

std::vector<pts> * dataPoints;//a pointer to the vector  

然后我在托管类的构造函数中在免费商店中创建了这个向量

dataPoints = new std::vector<pts>(noOfElements,pts());//which is not so attractive.

我需要向量的原因是因为我正在通过ifstream 读取文件并将这些值存储在向量中。
Q1)为什么我能够声明一个指向本机类型对象的指针(我猜)但不是一个对象? 此外,在尝试向量之前,我尝试了托管数组

cli::array<Point> dataPoints //and i defined it later.

但是当我这样做时

ifile >> dataPoints[i].X;   

它给出了一个错误 c2678 : operator= 没有为int 重载!!。
Q2)为什么我不能在这里使用托管代码。起初我认为它可能是一个包装类 Int 但随后自动拆箱(转换运算符)应该处理它?还是 Point::X 符合property 的条件,因此不被认为是正常的int?我错过了什么? 这就是我选择vectorpts 解决方案的原因。
pts 如下

 struct pts
{
  int X, int Y;
  pts() : X(0),Y(0){}
  pts(int x,int y) : X(x),Y(y){}
};//this i created to store the data from the file.

【问题讨论】:

标签: c++ visual-c++ stl managed-c++


【解决方案1】:

托管类对象的一个​​重要属性是它们被垃圾收集器移动。当它压缩堆时会发生这种情况。这对本机 C++ 对象造成严重破坏,指向其成员的指针将变得无效。因此,作为一项规则,编译器禁止将本机非 POD 对象嵌入托管对象中。指针不是问题。

在使用&gt;&gt; 运算符时存在完全相同的问题。 int 通过引用 operator>>() 来传递。如果垃圾收集器恰好在获取 int 引用的代码和调用操作符之间介入,那么灾难就会发生。一个简单的解决方法是通过局部变量的中间步骤:

int x;
ifile >> x;
dataPoint[i].X = x;

这很有效,因为局部变量是稳定的,不受垃圾回收的影响。

这在本机代码中都不是问题。请记住,您的 ref 类可以轻松调用本机函数。因此,将两者分开可能是有用的和/或必要的。

【讨论】:

  • 是的,而不是局部变量,我使用了向量,然后将数据加载到其中。这行得通。但还有一个问题是,为什么&gt;&gt; 的errorc2678 不应该是混合类型错误?
  • 此类问题的错误消息并不总是很重要。请注意 C2678 的 MSDN 库文章。引用:“如果在调用成员函数之前未固定本地成员,则可能会发生 C2678”
【解决方案2】:

您不能在托管类型中直接包含本机类型:这只是对 C++/CLI 的限制。我认为这可能与本机类型中指针的可能性有关。如果本机类型直接在托管类型中,那么当托管对象在垃圾回收期间被打乱时,这些指针将指向原来的、现在不正确的内存。

因此,本机对象需要在堆上,这样它的内部结构就不会被垃圾回收所改变。因此,您需要将向量作为指针保存,并适当地删除它。请注意,后者并非完全无关紧要,您需要对 C++/CLI(与 C# 略有不同)有所了解。见http://msdn.microsoft.com/en-us/library/ms177197(v=vs.100).aspx

查看我上次这样做的时间,在我的文件中

public:
    !NetClass();
    ~NetClass() { this->!NetClass(); } // avoid arning C4461
private:
    class NativeImpl* const m_pImpl; // can't contain NativeImpldirectly

在我拥有的 cpp 文件中

NetClass::!NetClass()
{
    // implement finalizer in ref class
    delete m_pImpl;
}

如果您要包含多个本地类,您可能只想在此处使用 pimpl 习惯用法。见Why should the "PIMPL" idiom be used?

最后,我上次这样做是很久以前的事了,我只是说当时对我有用的方法。如果你这样做,你真的需要知道你在做什么。我用了一本书叫C++/CLI in Action,我会推荐它。

编辑

这篇关于 STL/CLR 的文章看起来很有趣:http://blogs.msdn.com/b/nikolad/archive/2006/06/16/stlclr-intro.aspx。引用

STL/CLR,最初称为 STL.NET,是标准的实现 可以对托管类型的对象进行操作的模板库 (STL)。 VC++ 已经有 STL 的实现,但它目前是 仅适用于本机类型。

(我对您的 Q2 无能为力)

【讨论】:

  • 首先因为我在非托管代码上调用new,所以我应该在终结器而不是托管类的析构函数中使用delete,对吗?其次,如果我声明一个本机类型的对象,它应该分配在堆栈上,因此不能移动吗?
  • 是的,查看 msdn 链接以在终结器中删除(令人困惑的是“Visual C++ 终结器与 Finalize 方法不同(公共语言运行时文档使用终结器和 Finalize 方法的同义词)。”) .我认为您可以在堆栈上声明本机类型的对象。
猜你喜欢
  • 2011-01-29
  • 2010-12-10
  • 2012-09-23
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-03
  • 1970-01-01
相关资源
最近更新 更多