অন্তর্নিহিত যুক্তি রূপান্তর উপর নির্ভর করা বিপজ্জনক হিসাবে বিবেচিত হয়?


10

সি ++ এর একটি বৈশিষ্ট্য রয়েছে (আমি এর যথাযথ নামটি অনুমান করতে পারি না), যেগুলি আর্গুমেন্ট প্রকারগুলি প্রত্যাশিত না হলে স্বয়ংক্রিয়ভাবে প্যারামিটার ধরণের মিলকারী নির্মাতাদের কল করে।

এর একটি খুব মৌলিক উদাহরণ একটি ফাংশন কল করা std::stringযা একটি const char*যুক্তির সাথে প্রত্যাশা করে । সংকলক স্বয়ংক্রিয়ভাবে উপযুক্ত নির্মাতাকে ডাকতে কোড উত্পন্ন করবে std::string

আমি ভাবছি, পড়াশোনার পক্ষে কি এটি খারাপ বলে মনে হয়?

এখানে একটি উদাহরণ:

class Texture {
public:
    Texture(const std::string& imageFile);
};

class Renderer {
public:
    void Draw(const Texture& texture);
};

Renderer renderer;
std::string path = "foo.png";
renderer.Draw(path);

এটা কি ঠিক আছে? নাকি খুব বেশি দূর যায়? আমার যদি এটি না করা উচিত, আমি কি কোনওভাবে কলঙ্ক বা জিসিসি সম্পর্কে সতর্ক করতে পারি?


1
ড্র যদি পরে কোনও স্ট্রিং সংস্করণ দিয়ে ওভারলোড করা হত?
র‌্যাচেট ফ্রিক

1
@ ডেভ র্যাজারের উত্তর অনুসারে, আমি মনে করি না এটি সমস্ত সংকলকগুলিতে সংকলন করবে। তার উত্তর সম্পর্কে আমার মন্তব্য দেখুন। স্পষ্টতই, সি ++ স্ট্যান্ডার্ড অনুসারে আপনি এর মতো অন্তর্নিহিত রূপান্তরগুলি চেইন করতে পারবেন না। আপনি কেবল একটি রূপান্তর করতে পারবেন এবং আরও কিছু করতে পারবেন না।
জোনাথন হেনসন

ঠিক আছে দুঃখিত, আসলে এটি সংকলন করেন নি। উদাহরণ আপডেট করেছে এবং এটি এখনও ভয়াবহ, আইএমও।
futlib

উত্তর:


24

এটিকে রূপান্তরকারী কনস্ট্রাক্টর (বা কখনও কখনও অন্তর্নিহিত কনস্ট্রাক্টর বা অন্তর্নিহিত রূপান্তর) হিসাবে উল্লেখ করা হয়।

যখন এটি ঘটে তখন আমি সতর্ক করতে সংকলিত-সময় স্যুইচ সম্পর্কে অবগত নই, তবে এটি প্রতিরোধ করা খুব সহজ; শুধু explicitকীওয়ার্ডটি ব্যবহার করুন ।

class Texture {
public:
    explicit Texture(const std::string& imageFile);
};

কনস্ট্রাক্টর রূপান্তরকারী একটি ভাল ধারণা কিনা তা নির্ভর করে: এটি নির্ভর করে।

এমন পরিস্থিতি যেখানে অন্তর্নিহিত রূপান্তরটি বোঝায়:

  • বর্গটি নির্মাণের জন্য যথেষ্ট সস্তা যে এটি পরোক্ষভাবে নির্মাণ করা থাকলে আপনার যত্ন নেই।
  • কিছু শ্রেণি ধারণাগতভাবে তাদের যুক্তিগুলির std::stringসাথে সমান (যেমন একই ধারণাটিকে প্রতিচ্ছবি হিসাবে const char *এটি স্পষ্টভাবে রূপান্তর করতে পারে), সুতরাং অন্তর্নিহিত রূপান্তরটি বোঝায়।
  • অন্তর্নিহিত রূপান্তর অক্ষম করা থাকলে কিছু শ্রেণি ব্যবহার করতে অনেক বেশি অপ্রিয় হয়ে ওঠে। (আপনি যখনই স্ট্রিংকে আক্ষরিক পাস করতে চান প্রতিটি সময় স্পষ্টভাবে স্ট্রাইড :: স্ট্রিংয়ের অনুরোধ করার কথা ভাবেন B বুস্টের অংশগুলি একই রকম)

এমন পরিস্থিতিতে যেখানে অন্তর্নিহিত রূপান্তরটি কম বোঝায়:

  • নির্মাণ ব্যয়বহুল (যেমন আপনার টেক্সচার উদাহরণ, যার জন্য একটি গ্রাফিক ফাইল লোড করা এবং পার্স করা প্রয়োজন)।
  • ক্লাসগুলি তাদের যুক্তিগুলির সাথে ধারণাগতভাবে খুব আলাদা। উদাহরণস্বরূপ, একটি অ্যারের মতো ধারক বিবেচনা করুন যা তার আকারটিকে একটি আর্গুমেন্ট হিসাবে গ্রহণ করে:
    ক্লাস ফ্ল্যাগলিস্ট
    {
        ফ্ল্যাগলিস্ট (int প্রাথমিক_ আকার); 
    };

    অকার্যকর সেটফ্ল্যাগস (কনস্ট্যান্ড ফ্ল্যাগলিস্ট এবং ফ্ল্যাগ_লিস্ট);

    int প্রধান () {
        // এখন এটি সংকলন করে, যদিও তা একেবারেই স্পষ্ট নয়
        // এটি কি করছে।
        SetFlags (42);
    }
  • নির্মাণে অযাচিত পার্শ্ব প্রতিক্রিয়া থাকতে পারে। উদাহরণস্বরূপ, কোনও AnsiStringশ্রেণীর একটি থেকে স্পষ্টভাবে নির্মাণ করা উচিত নয়UnicodeString , যেহেতু ইউনিকোড থেকে এএনএসআই রূপান্তর তথ্য হারাতে পারে।

আরও পড়া:


3

এটি উত্তরের চেয়ে কমেন্টের চেয়ে বেশি তবে একটি মন্তব্য করা খুব বড়।

মজার বিষয়, g++আমাকে এটি করতে দেয় না:

#include <iostream>
#include <string>

class Texture {
        public:
                Texture(const std::string& imageFile)
                {
                        std::cout << "Texture()" << std::endl;
                }
};

class Renderer {
        public:
                void Draw(const Texture& texture)
                {
                        std::cout << "Renderer.Draw()" << std::endl;
                }
};

int main(int argc, char* argv[])
{
        Renderer renderer;
        renderer.Draw("foo.png");

        return 0;
}

নিম্নলিখিত উত্পাদন করে:

$ g++ -o Conversion.exe Conversion.cpp 
Conversion.cpp: In function int main(int, char**)’:
Conversion.cpp:23:25: error: no matching function for call to Renderer::Draw(const char [8])’
Conversion.cpp:14:8: note: candidate is: void Renderer::Draw(const Texture&)

তবে, আমি যদি লাইনটি এতে পরিবর্তন করি:

   renderer.Draw(std::string("foo.png"));

এটি সেই রূপান্তরটি সম্পাদন করবে।


এটি আসলে জি ++ এর একটি আকর্ষণীয় "বৈশিষ্ট্য"। আমি মনে করি এটি হ'ল একটি বাগ যা সঠিক কোড উত্পন্ন করতে সংকলনের সময় যতটা সম্ভব পুনরাবৃত্তভাবে নীচে যাওয়ার পরিবর্তে কেবল এক প্রকারের গভীরতা পরীক্ষা করে, বা এমন একটি পতাকা রয়েছে যা আপনার জি ++ কমান্ডে সেট করা দরকার।
জোনাথন হেনসন

1
en.cppreferences.com/w/cpp/language/impLive_cast দেখে মনে হচ্ছে জি ++ মানকটিকে কঠোরভাবে অনুসরণ করছে following এটি মাইক্রোসফ্ট বা ম্যাকের সংকলক যা ওপি কোডের সাথে কিছুটা উদার হচ্ছে। বিশেষত বক্তব্যটি বলা হচ্ছে: "কোনও কনস্ট্রাক্টর বা ব্যবহারকারী-সংজ্ঞায়িত রূপান্তর ফাংশনের পক্ষে যুক্তি বিবেচনা করার সময়, কেবলমাত্র একটি স্ট্যান্ডার্ড রূপান্তর ক্রমের অনুমতি দেওয়া হয় (অন্যথায় ব্যবহারকারী-সংজ্ঞায়িত রূপান্তরগুলি কার্যকরভাবে শৃঙ্খলাবদ্ধ হতে পারে)"
জোনাথন হেনসন

হ্যাঁ, আমি কয়েকটি gccসংকলক বিকল্পগুলি পরীক্ষা করার জন্য কোডটি একসাথে ছুঁড়েছি (যা দেখে মনে হচ্ছে না যে এই নির্দিষ্ট ক্ষেত্রে সম্বোধনের জন্য কোনও আছে)) আমি এটির দিকে আরও বেশি তাকাতে পারি নি (আমার কাজ করার কথা :-) তবে gccমানটির সাথে সম্মতি দেওয়া এবং explicitকীওয়ার্ডের ব্যবহারটি একটি সংকলক বিকল্প সম্ভবত অপ্রয়োজনীয় বলে মনে করা হয়েছিল।
ডেভ র্যাজার

অন্তর্নিহিত রূপান্তরগুলি শৃঙ্খলাবদ্ধ নয় এবং Textureসম্ভবত একটি স্পষ্টভাবে নির্মাণ করা উচিত নয় (অন্যান্য উত্তরগুলির গাইডলাইন অনুসারে), সুতরাং একটি ভাল কল-সাইট হবে renderer.Draw(Texture("foo.png"));(এটি আমার প্রত্যাশা অনুযায়ী কাজ করে)।
ব্লেজারব্লেড

3

একে অন্তর্নিহিত ধরণের রূপান্তর বলা হয়। সাধারণভাবে এটি একটি ভাল জিনিস, কারণ এটি অপ্রয়োজনীয় পুনরাবৃত্তি বাধা দেয়। উদাহরণস্বরূপ, আপনি এটির জন্য কোনও অতিরিক্ত কোড না লিখে স্বয়ংক্রিয়ভাবে একটি std::stringসংস্করণ Drawপান। এটি মুক্ত-বদ্ধ নীতি অনুসরণ করতে সহায়তা করতে পারে, কারণ এটি আপনাকে নিজের Rendererপরিবর্তন না করেই এর ক্ষমতা বাড়িয়ে দেয় Renderer

অন্যদিকে, এটি কোনও ত্রুটিগুলি ছাড়াই নয়। কোনও কিছুর জন্য যুক্তিটি কোথা থেকে এসেছে তা নির্ধারণ করা কঠিন করে তুলতে পারে। এটি কখনও কখনও অন্যান্য ক্ষেত্রে অপ্রত্যাশিত ফলাফল আনতে পারে। যে কি explicitশব্দ জন্য। আপনি যদি এটি Textureকন্সট্রাক্টরের উপর রাখেন তবে অন্তর্ভুক্ত প্রকারের রূপান্তরের জন্য সেই কনস্ট্রাক্টর ব্যবহার করে এটি অক্ষম করে। অন্তর্নিহিত ধরণের রূপান্তর সম্পর্কে বিশ্বব্যাপী সতর্ক করার কোনও পদ্ধতির বিষয়ে আমি অবগত নই, তবে এর অর্থ এই নয় যে কোনও পদ্ধতি বিদ্যমান নেই, কেবলমাত্র জিসিসির কাছে বোধগম্যভাবে বিশাল সংখ্যক বিকল্প রয়েছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.