VS2015 的第一步,使用 C++。 Managed/Unmanaged 类 错误。我做错了什么?

First steps with VS2015, using C++. Managed/Unmanaged Classes error. What I'm doing wrong?

我在工作中使用 C++Builder 2006 开发了一个个人项目。 现在我想在家里开发它,使用免费的东西。所以我安装了 Visual Studio 2015(作为第二选择,因为我未能使 Codelite+wxWidgets 工作)并开始了一个新的解决方案/CLR 项目。

但我正在为一个错误而苦苦思索。 这就是我所拥有的;

cSQSequencer class,使用添加->Class 向导创建。

cSQSequencer.h

#pragma once
#include <string>

class cSQSequencer
{
public:
    cSQSequencer();
    ~cSQSequencer();
    std::string         Name;
    void    Reset() {
        Name="";
    };
};

cSQSequencer.cpp

#include "cSQSequencer.h"

cSQSequencer::cSQSequencer()
{
}

cSQSequencer::~cSQSequencer()
{
}

然后我有一个表格,我搜索了一种方法来使用一些向导来添加我的 class,比如添加功能,但我找到了任何东西,所以我手动添加了与我的 [=44] 相关的行=]:

SysExExpMainForm

#pragma once
#include "cSQSequencer.h"

namespace EnsoniqSQKSSysExexporter {

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;

    /// <summary>
    /// Riepilogo per SysExExpMainForm
    /// </summary>

    public ref class SysExExpMainForm : public System::Windows::Forms::Form
    {
    public:
        cSQSequencer SQSeq;
        SysExExpMainForm(void)
        {
            InitializeComponent();
            //
            //TODO: aggiungere qui il codice del costruttore.
            //
            SQSeq.Reset();
        }

    protected:
    [ all the other code that follows.... ]

错误在行 "cSQSequencer SQSeq;" 中。它说(或多或少,从意大利语翻译回来)"A member of a managed class cannot be a non-managed type"。

我该怎么办? 这是在表单中添加 class 变量的正确方法吗? 或者我应该开始不同类型的项目(但这是我找到的唯一可以添加表格的项目....)

    cSQSequencer SQSeq;

您得到的错误消息对于此声明是准确的,使用本机 C++ 对象作为垃圾收集对象的成员,如 Form,是非常非常危险的。非常危险,语言扩展完全禁止它。

垃圾收集对象发生的可能不明显的事情是它们可以在内存中移动。当收集器 compacts 收集通过后堆时会发生这种情况。压缩使堆非常有效,改善了引用的局部性并防止了碎片。

收集器更新任何指向此类移动对象的指针,以将它们重新指向移动的对象。但这只适用于收集器知道的指针。托管指针。不是本机 C++ 对象使用的指针,它们仍将指向此类本机对象曾经存在的位置。现在指着垃圾。在您当前的 cSQSequencer class 中没有太大的危险,我们无论如何都可以看到,但可能不会一直这样。请注意,std::string 成员已经是一个问题,一个模板 class 内部包含指向底层字符串缓冲区的指针。

太危险了,编译器直接禁止了。您必须改用的是指向本机对象的指针或引用。它现在指的是不是从 GC 堆分配的内存,因此是稳定的。所以你需要:

    cSQSequencer* SQSeq;

然后跳舞来创造和摧毁它:

    MyForm(void) : SQSeq(new cSQSequencer) {
        // etc... 
    }

    ~MyForm() {
        delete SQSeq;
        SQSeq = nullptr;
        // etc..
    }

    !MyForm() {
        delete SQSeq;
    }

请注意 class、!MyForm()finalizer,它确保无论客户端代码是否正确处置对象,都会进行清理。或者换句话说,如果它忘记使用 delete 运算符,那么终结器会确保它无论如何都会发生。在本机 C++ 中没有等效项。从技术上讲,您可以在这种特定情况下忽略它,Form 对象有很好的处理保证,Winforms 运行time 会处理它。但是无论如何都要养成习惯,总有一天你不会失望的。

此代码可能会让您惊呼 "smart pointer"。例如 Nish's CAutoNativePtr and Kenny Kerr's AutoPtr.

另请阅读 this post to know how to properly transmogrify a console app project template to support a UI. There's a lot of 那里弄错了,这也是您不应在析构函数中省略 SQSeq = nullptr 赋值的原因。与原生 C++ 非常不同,析构函数可以 运行 不止一次。只有终结器保证 运行 一次。