【问题标题】:Array converted implicitly to container class when passed as argument in C++在 C++ 中作为参数传递时,数组隐式转换为容器类
【发布时间】:2012-02-18 04:16:53
【问题描述】:

我正在做一个项目,在玩弄代码时,我遇到了以下奇怪的情况。

我有两节课。第一个在表示笛卡尔坐标的数组中保存三个浮点数,并定义了获取这些点的方法;

class foo
{
protected:
    float m_Coordinates[3];

public:
    foo(float coordinates[3]);
    void GetPoints(int resultArray[]);
};

foo::foo(int coordinates[3])
{
    std::copy(coordinates, coordinates+3, m_Coordinates);
}

void foo::GetPoints(float resultArray[])
{
    std::copy(m_Coordinates, m_Coordinates+3, resultArray);
}

第二个类也存储一个浮点数组,但它的构造函数使用 foo 作为包装类来传递值:

class bar
{
protected:
    float m_MoreCoordinates[3];

public:
    bar(foo f);
};

bar::bar(foo f)
{
    f.GetPoints(m_MoreCoordinates);
    //m_MoreCoordinates is passed by reference, so the values in
    //m_MoreCoordinates are equal to the values in f.m_Coordinates
    //after this line executes
}

请忽略这样一个事实,即我对这段代码采用的方法简直太可怕了。它最初是一个使用数组的实验。将它们作为参数传递,将它们作为返回类型等。

好的。这是我注意到一些奇怪的地方。如果我声明一个浮点数组并将它们作为参数传递给 bar 的构造函数,编译器将生成类 foo 的实例并将其传递给 bar。请参阅下面的示例代码:

int main(int argv, char** argc)
{
    float coordinates[] = {1.0f, 2.1f, 3.0f};


    //Here the compiler creates an instance of class foo and passes 
    //coordinates as the argument to the constructor. It then passes 
    //the resulting class to bar's constructor.
    bar* b = new bar(coordinates);

    //Effectively, the compiler turns the previous line into
    //bar* b = new bar(foo(coordinates));

    return 0;
}

当我看到这个时,我认为这是代码的一个非常简洁的功能,并且想知道它是如何以及为什么会发生的。这样做安全吗?我不明白它是如何工作的,所以我不想依赖它。如果有人能解释这是如何工作的,我将不胜感激。

编辑: 感谢 Mankarse 指出主要如何进行转换。最初,我有:

//Effectively, the compiler turns the previous line into
//bar* b = new bar(*(new foo(coordinates)));

【问题讨论】:

  • 编译器实际上把这行变成了bar* b = new bar(foo(coordinates));
  • @Mankarse 是对的,bar* b = new bar(*(new foo(coordinates)));由于构造函数按值传递,因此会泄漏。你永远没有机会清理它。
  • @Mankarse 啊,感谢您指出这一点。 Java简直毁了我。我从来没有注意到那里会有内存泄漏。

标签: c++ arrays constructor instantiation implicit


【解决方案1】:

如您所料,编译器隐式创建了一个foo 对象并将其传递给bar。一般来说,这被认为有点危险,因为foo 是在不知情的情况下构造的,为避免这种情况,您可以将foos 构造函数声明为explicit。在这种情况下,编译器不会从浮点数组隐式创建foo,您将收到编译器错误。

【讨论】:

  • 非常感谢。这是编译器的有趣行为。我以前从未见过它这样做。谢谢你的解释。
  • 人们认为具有非托管内存的语言是不安全的。这并不意味着它们不应该被用作一种无价的语言,只是你应该在使用它们之前知道你在做什么。
【解决方案2】:

当您想到它时,您一直在使用它。考虑以下几点:

void foo(std::string argument);

然后,假设您使用字符串文字调用此函数:

foo("argument");

这与:

std::string argument("argument");
foo(argument);

这是一个非常有用的功能。

【讨论】:

  • 所以我们总是可以依赖编译器来为我们执行这个转换?你是对的,这是一个非常有用的功能。尽管 Naveen 建议谨慎使用它似乎是个好建议。即使从可读性的角度来看,依靠编译器从浮点数组创建类也不是很清晰的编码。尽管如此,这是一个非常有趣的功能。
  • @GaryMunnelly 我认为您可以在函数定义中传递类型的构造参数非常清晰易读。事实上,我认为正确使用它通常会使代码更具可读性。无论如何,各有各的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-27
  • 1970-01-01
  • 2011-11-19
  • 2017-03-19
  • 2011-12-30
相关资源
最近更新 更多